diff --git a/research/cv/pcb/README.md b/research/cv/pcb/README.md new file mode 100644 index 0000000000000000000000000000000000000000..53bee06316099edb07ec8d0fadad5fddc78b14fe --- /dev/null +++ b/research/cv/pcb/README.md @@ -0,0 +1,984 @@ +# Contents + +- [Contents](#contents) +- [PCB Description](#pcb-description) + - [Description](#description) + - [Paper](#paper) +- [Model Architecture](#model-architecture) +- [Dataset](#dataset) +- [Features](#features) + - [Mixed Precision](#mixed-precision) +- [Environment Requirements](#environment-requirements) +- [Quick Start](#quick-start) +- [Script Description](#script-description) + - [Script and Sample Code](#script-and-sample-code) + - [Script Parameters](#script-parameters) + - [Training Process](#training-process) + - [Usage](#usage) + - [Running on Ascend](#running-on-ascend) + - [Result](#result) + - [Evaluation Process](#evaluation-process) + - [Usage](#usage-1) + - [Running on Ascend](#running-on-ascend-1) + - [Result](#result-1) + - [Inference Process](#inference-process) + - [Export MindIR](#export-mindir) + - [Infer on Ascend310](#infer-on-ascend310) + - [Result](#result-2) +- [Model Description](#model-description) + - [Performance](#performance) + - [Evaluation Performance](#evaluation-performance) + - [PCB on Market-1501](#pcb-on-market-1501) + - [PCB on DukeMTMC-reID](#pcb-on-dukemtmc-reid) + - [PCB on CUHK03](#pcb-on-cuhk03) + - [PCB-RPP on Market-1501](#pcb-rpp-on-market-1501) + - [PCB-RPP on DukeMTMC-reID](#pcb-rpp-on-dukemtmc-reid) + - [PCB-RPP on CUHK03](#pcb-rpp-on-cuhk03) +- [Description of Random Situation](#description-of-random-situation) +- [ModelZoo Homepage](#modelzoo-homepage) + +# PCB Description + +## Description + +PCB (Part-level Convolutional Baseline) is a classic model for Person Re-Identification. Given an image input, it outputs a convolutional descriptor consisting of several part-level features. Moreover, a refined part pooling (RPP) method is proposed to re-assign the outliers incurred by the uniform partition strategy to the parts they are closest to, resulting in refined parts +with enhanced within-part consistency. + +## Paper + +1.[paper](https://arxiv.org/pdf/1711.09349.pdf):Yifan Sun, Liang Zheng, Yi Yang, Qi Tian, Shengjin Wang."Beyond Part Models: Person Retrieval with Refined Part Pooling (and A Strong Convolutional Baseline)" + +# Model Architecture + +The overall network architecture of PCB is shown below: +[Link](https://arxiv.org/pdf/1711.09349.pdf) + +# Dataset + +Dataset used: [Market-1501](<http://zheng-lab.cecs.anu.edu.au/Project/project_reid.html>) +[Download Link](https://pan.baidu.com/s/1qWEcLFQ?_at_=1640837580475) + +- Dataset size: + - Training Set:12936 RGB images containing 751 pedestrians + - Test Set: + + -query set: 3368 RGB images containing 750 pedestrians + + -gallery set:15913 RGB images containing 751 pedestrians + +- Data format:PNG + - Note:Data will be processed in src/datasets/market.py +- Download the dataset, the directory structure is as follows: + +```text +├─ Market-1501 + │ + ├─bounding_box_test + │ + └─bounding_box_train + │ + └─gt_bbx + │ + └─gt_query + │ + └─query +``` + +Dataset used: [DukeMTMC-reID](http://vision.cs.duke.edu/DukeMTMC/) +[Download Link](https://pan.baidu.com/share/init?surl=jS0XM7Var5nQGcbf9xUztw) Access code:bhbh + +- Dataset size: + - training set:16522 RGB images containing 702 pedestrians + - test set: + + -query set: 2228 RGB images containing 702 pedestrians + + -gallery set:17661 RGB images containing 1110 pedestrians + +- Data format:PNG + - Note:Data will be processed in src/datasets/duke.py +- Download the dataset, the directory structure is as follows: + +```text +├─ DukeMTMC-reID + │ + ├─bounding_box_test + │ + └─bounding_box_train + │ + └─query +``` + +Dataset used:[CUHK03](<http://www.ee.cuhk.edu.hk/~xgwang/CUHK_identification.html>) +[Download Link](https://pan.baidu.com/s/1o8txURK) + +The paper adopts [the new training/testing protocol](https://github.com/zhunzhong07/person-re-ranking/tree/master/CUHK03-NP) +The new protocol splits the CUHK03 dataset into training set and testing set similar to that of Market-1501 +[Download link of the new training/testing protocol split for CUHK03](https://drive.google.com/file/d/0B7TOZKXmIjU3OUhfd3BPaVRHZVE/view?resourcekey=0-hU4gyE6hFsBgizIh9DFqtA) + +- Dataset size of CUHK03 in the new protocol + - Training set:7365 RGB images containing 767 pedestrians + - Test set: + + -query set: 1400 RGB images containing 700 pedestrians + + -gallery set:5332 RGB images containing 700 pedestrians + +- Data format:PNG + - Note:Data will be processed in src/datasets/cuhk03.py + +- Note: After downloading the CUHK03 dataset and the new training/testing protocol split, please organize the cuhk03.mat (in original dataset) and cuhk03_new_protocol_config_detected.mat (in the new training/testing protocol split) as follows. + +```text +├─ CUHK03 + │ + ├─ cuhk03.mat + │ + └─ cuhk03_new_protocol_config_detected.mat +``` + +- Pretrained Resnet50 checkpoint file [Download Link](https://gitee.com/starseekerX/PCB_pretrained_checkpoint/blob/master/pretrained_resnet50.ckpt) + +# Features + +## Mixed Precision + +The [mixed precision](https://www.mindspore.cn/docs/programming_guide/en/r1.6/enable_mixed_precision.html) training method accelerates the deep learning neural network training process by using both the single-precision and half-precision data types, and maintains the network precision achieved by the single-precision training at the same time. Mixed precision training can accelerate the computation process, reduce memory usage, and enable a larger model or batch size to be trained on specific hardware. +For FP16 operators, if the input data type is FP32, the backend of MindSpore will automatically handle it with reduced precision. Users could check the reduced-precision operators by enabling INFO log and then searching ‘reduce precision’. + +# Environment Requirements + +- Hardware(Ascend) + - Prepare hardware environment with Ascend +- Framework + - [MindSpore](https://www.mindspore.cn/install/en) +- For more information, please check the resources below: + - [MindSpore Tutorials](https://www.mindspore.cn/tutorials/en/master/index.html) + - [MindSpore Python API](https://www.mindspore.cn/docs/api/en/master/index.html) + +# Quick Start + +After installing MindSpore via the official website, you can start training and evaluation as follows: + +> - <font size=2>During training, evaluating and inferring, if Market-1501 dataset is used, DATASET_PATH={Market-1501 directory};if DukeMTMC-reID dataset is used, DATASET_PATH={DukeMTMC-reID directory};if CUHK03 dataset is used, DATASET_PATH={CUHK03 directory} </font> + +- Running on Ascend + +```bash +# standalone training +# Usage: +bash run_standalone_train.sh [MODEL_NAME] [DATASET_NAME] [DATASET_PATH] [CONFIG_PATH] [PRETRAINED_CKPT_PATH](optional) + +# Example: +bash run_standalone_train.sh PCB market ../../Datasets/Market-1501 ../config/train_PCB_market.yaml ../../pretrained_resnet50.ckpt + +# Distributed training +# Usage: +bash run_distribute_train.sh [RANK_TABLE_FILE] [MODEL_NAME] [DATASET_NAME] [DATASET_PATH] [CONFIG_PATH] [PRETRAINED_CKPT_PATH](optional) + +# Example: +bash run_distribute_train.sh ../hccl_8p_01234567_127.0.0.1.json PCB market ../../Datasets/Market-1501 ../config/train_PCB_market.yaml ../../pretrained_resnet50.ckpt + +# Evaluation +# Usage: +bash run_eval.sh [MODEL_NAME] [DATASET_NAME] [DATASET_PATH] [CONFIG_PATH] [CHECKPOINT_PATH] [USE_G_FEATURE] + +# Example: +bash run_eval.sh PCB market ../../Datasets/Market-1501 ../config/eval_PCB_market.yaml ./output/checkpoint/PCB/market/train/PCB-60_202.ckpt True +``` + +# Script Description + +## Script and Sample Code + +```text +. +└──PCB + ├── README.md + ├── config # parameter + ├── base_config.yaml + ├── train_PCB_market.yaml + ├── train_PCB_duke.yaml + ├── train_PCB_cuhk03 + ├── train_PCB.yaml + ├── finetune_PCB.yaml + ├── train_RPP_market + ├── train_PCB.yaml + ├── train_RPP.yaml + ├── train_RPP_duke + ├── train_PCB.yaml + ├── train_RPP.yaml + ├── train_RPP_cuhk03 + ├── train_PCB.yaml + ├── train_RPP.yaml + ├── finetune_RPP.yaml + ├── eval_PCB_market.yaml + ├── eval_PCB_duke.yaml + ├── eval_PCB_cuhk03.yaml + ├── eval_RPP_market.yaml + ├── eval_RPP_duke.yaml + ├── eval_RPP_cuhk03.yaml + ├── infer_310_config.yaml + ├── scripts + ├── run_standalone_train.sh # launch standalone training + ├── run_distribute_eval.sh # launch distributed training + ├── run_eval.sh # launch evaluation + ├── run_infer_310.sh # launch 310 inference + ├── src + ├── dataset.py # dataset preprocessing + ├── eval_callback.py # evaluation callback while training + ├── eval_utils.py # evaluation utility function (calculate CMC, mAP) + ├── meter.py + ├── logging.py + ├── lr_generator.py # generate learning rate for each step + ├── pcb.py # PCB + ├── rpp.py # PCB+RPP + ├── resnet.py # resnet50 backbone + ├── datasets # Utility function for processing datasets + ├── market.py + ├── duke.py + ├── cuhk03.py + ├── model_utils + ├── config.py # parameter configuration + ├── device_adapter.py # device adapter + ├── local_adapter.py # local adapter + └── moxing_adapter.py # moxing adapter + ├── eval.py # eval net + └── train.py # train net + └── export.py # export model for inference + └── preprocess.py # preprocess input data for 310 inference + └── postprocess.py # postprocess result from 310 inference and calculate metrics +``` + +## Script Parameters + +Parameters for both training, evaluation, model exportation and inference can be set in config file. + +- Config for training PCB on Market-1501 dataset + +```text +enable_modelarts: False # whether to use modelarts or not +data_url: "" +train_url: "" +checkpoint_url: "" +run_distribute: False # whether to run distributed training or not +enable_profiling: False +dataset_path: "/cache/dataset/" # dataset path +output_path: "/cache/output/" # output path +load_path: "/cache/load_checkpoint/" +device_target: "Ascend" +log_save_path: "./log/PCB/market/train" # path for saving log +checkpoint_save_path: "./checkpoint/PCB/market/train" # path for saving checkpoint +checkpoint_file_path: "/cache/load_checkpoint/pretrained_resnet50.ckpt" # path for loading checkpoint + +mindrecord_dir: "./MindRecord" # path for saving MindRecord file +dataset_name: "market" # short name of the dataset +batch_size: 64 # batch size of input tensor +num_parallel_workers: 4 +device_num: 1 # number of the available devices + +model_name: "PCB" # short name of the model +learning_rate: 0.1 # learning rate +lr_mult: 0.1 # multiple for controlling the backbone learning rate +decay_rate: 0.1 # decay rate of the learning rate +momentum: 0.9 # momentum of SGD +weight_decay: 5e-4 # weight decay of SGD +nesterov: True + +mode_name: "GRAPH" # whether to use GRAPTH mode or use PYNATIVE mode +sink_mode: True # whether to start data sink mode +seed: 37 # random seed +epoch_size: 60 # epoch size for training +decay_epoch_size: 40 # interval size for learning rate decay +warmup_epoch_size: 1 # epoch size for warmup + +save_checkpoint: True # whether to save checkpoint +save_checkpoint_epochs: 60 # epoch size for saving checkpoint +keep_checkpoint_max: 15 # maximum number of the saved checkpoints + +run_eval: False # whether to run evaluation during training +eval_interval: 15 # evaluation interval size +eval_start_epoch: 60 # start epoch for evaluation +use_G_feature: True # whether to use G feature or use H feature for evaluation +``` + +- Config for evaluating PCB on Market-1501 dataset + +```text +enable_modelarts: False +data_url: "" +train_url: "" +checkpoint_url: "" +enable_profiling: False +dataset_path: "/cache/dataset/" +output_path: "/cache/output/" +load_path: "/cache/load_checkpoint/" +device_target: "Ascend" +log_save_path: "./log/PCB/market/eval" +checkpoint_file_path: "/cache/load_checkpoint/PCB-60_202.ckpt" + +mindrecord_dir: "./MindRecord" +dataset_name: "market" +batch_size: 64 # batch size of the input tensor +num_parallel_workers: 4 + +model_name: "PCB" +use_G_feature: True # whether to use G feature or use H feature for evaluation +``` + +- Config for exporting PCB and running 310 inference + +```text +enable_modelarts: False +data_url: "" +train_url: "" +checkpoint_url: "" +enable_profiling: False +dataset_path: "/cache/dataset/" +output_path: "/cache/output/" +load_path: "/cache/load_checkpoint/" +device_target: "Ascend" +checkpoint_file_path: "/cache/load_checkpoint/PCB-60_202.ckpt" +batch_size: 1 # Currently, only support batch size==1 +model_name: "PCB" +use_G_feature: True # whether to use G feature or use H feature for evaluation + +device_id: 0 +image_height: 384 # height of the input image +image_width: 128 # width of the input image +file_name: "export_PCB_market_G" # name of the exported model +file_format: "MINDIR" # file format of the exported model + +preprocess_result_path: "./preprocess_Result" #path for saving preprocess result + +query_prediction_path: "./query_result_files" #path for saving inference result of the query set +gallery_prediction_path: "./gallery_result_files" #path for saving inference result of the gallery set +``` + +## Training Process + +### Usage + +#### Running on Ascend + +```bash +# Standalone training +# Usage: +bash run_standalone_train.sh [MODEL_NAME] [DATASET_NAME] [DATASET_PATH] [CONFIG_PATH] [PRETRAINED_CKPT_PATH] (optional) +# MODEL_NAME should be in ['PCB', 'RPP'], DATASET_NAME should be in ['market', 'duke', 'cuhk03']. + +# Examples: + +# 1. Training PCB on Market-1501 + +bash run_standalone_train.sh PCB market ../../Datasets/Market-1501 ../config/train_PCB_market.yaml ../../pretrained_resnet50.ckpt + +# 2. Training PCB on DukeMTMC-reID + +bash run_standalone_train.sh PCB duke ../../Datasets/DukeMTMC-reID ../config/train_PCB_duke.yaml ../../pretrained_resnet50.ckpt + +# 3. Training PCB on CUHK03 + +bash run_standalone_train.sh PCB cuhk03 ../../Datasets/CUHK03 ../config/train_PCB_cuhk03 ../../pretrained_resnet50.ckpt + +# 4. Training PCB+RPP on Market-1501 + +bash run_standalone_train.sh RPP market ../../Datasets/Market-1501 ../config/train_RPP_market ../../pretrained_resnet50.ckpt + +# 5. Training PCB+RPP on DukeMTMC-reID + +bash run_standalone_train.sh RPP duke ../../Datasets/DukeMTMC-reID ../config/train_RPP_duke ../../pretrained_resnet50.ckpt + +# 6. Training PCB+RPP on CUHK03 + +bash run_standalone_train.sh RPP cuhk03 ../../Datasets/CUHK03 ../config/train_RPP_cuhk03 ../../pretrained_resnet50.ckpt + + +# Distributed training +# Usage: +bash run_distribute_train.sh [RANK_TABLE_FILE] [MODEL_NAME] [DATASET_NAME] [DATASET_PATH] [CONFIG_PATH] [PRETRAINED_CKPT_PATH] (optional) +# MODEL_NAME should be in ['PCB', 'RPP'], DATASET_NAME should be in ['market', 'duke', 'cuhk03']. + +# Examples: + +# 1. Training PCB on Market-1501 + +bash run_distribute_train.sh ../hccl_8p_01234567_127.0.0.1.json PCB market ../../Datasets/Market-1501 ../config/train_PCB_market.yaml ../../pretrained_resnet50.ckpt + +# 2. Training PCB on DukeMTMC-reID + +bash run_distribute_train.sh ../hccl_8p_01234567_127.0.0.1.json PCB duke ../../Datasets/DukeMTMC-reID ../config/train_PCB_duke.yaml ../../pretrained_resnet50.ckpt + +# 3. Training PCB on CUHK03 + +bash run_distribute_train.sh ../hccl_8p_01234567_127.0.0.1.json PCB cuhk03 ../../Datasets/CUHK03 ../config/train_PCB_cuhk03 ../../pretrained_resnet50.ckpt + +# 4. Training PCB+RPP on Market-1501 + +bash run_distribute_train.sh ../hccl_8p_01234567_127.0.0.1.json RPP market ../../Datasets/Market-1501 ../config/train_RPP_market ../../pretrained_resnet50.ckpt + +# 5. Training PCB+RPP on DukeMTMC-reID + +bash run_distribute_train.sh ../hccl_8p_01234567_127.0.0.1.json RPP duke ../../Datasets/DukeMTMC-reID ../config/train_RPP_duke ../../pretrained_resnet50.ckpt + +# 6. Training PCB+RPP on CUHK03 + +bash run_distribute_train.sh ../hccl_8p_01234567_127.0.0.1.json RPP cuhk03 ../../Datasets/CUHK03 ../config/train_RPP_cuhk03 ../../pretrained_resnet50.ckpt +``` + +For distributed training, a hccl configuration file with JSON format needs to be created in advance. + +Please follow the instructions in the link [hccl_tools](https://gitee.com/mindspore/models/tree/master/utils/hccl_tools). + +Training result will be stored in the "output" directory. specifically, the training log will be stored in "./output/log/{MODEL_NAME}/{DATASET_NAME}/train" and the checkpoints will be stored in "./output/checkpoint/{MODEL_NAME}/{DATASET_NAME}/train." + +#### Modelarts Training Job + +If you want to run in modelarts, please check the official documentation of [modelarts](https://support.huaweicloud.com/modelarts/), and you can start standalone training and distributed training as follows: + +```text +# run standalone training on modelarts example +# (1) Add "config_path='/path_to_code/config/train_PCB_market.yaml'" on the website UI interface. +# (2) First, Perform a or b. +# a. Set "enable_modelarts=True" in yaml file. +# Set "checkpoint_file_path='/cache/load_checkpoint/model.ckpt" in yaml file. +# Set "checkpoint_url=/The path of checkpoint in S3/" in yaml file. +# Set other parameters you need in yaml file. +# b. Add "enable_modelarts=True" on the website UI interface. +# Add "checkpoint_file_path='/cache/load_checkpoint/model.ckpt'" on the website UI interface. +# Add "checkpoint_url=/The path of checkpoint in S3/" on the website UI interface. +# Add other parameters you need on the website UI interface. +# (3) Set the code directory to "/path/PCB" on the website UI interface. +# (4) Set the startup file to "train.py" on the website UI interface. +# (5) Set the "Dataset path" and "Output file path" and "Job log path" to your path on the website UI interface. +# (6) Create your job. + +# run distributed training on modelarts example +# (1) Add "config_path='/path_to_code/config/train_PCB_market.yaml'" on the website UI interface. +# (2) First, Perform a or b. +# a. Set "enable_modelarts=True" in yaml file. +# Set "checkpoint_file_path='/cache/load_checkpoint/model.ckpt" in yaml file. +# Set "checkpoint_url=/The path of checkpoint in S3/" in yaml file. +# Set "run_distribute=True" in yaml file. +# Set "device_num = {number of the available devices}" in yaml file. +# Set other parameters you need in yaml file.。 +# b. Add "enable_modelarts=True" on the website UI interface. +# Add "checkpoint_file_path='/cache/load_checkpoint/model.ckpt'" on the website UI interface. +# Add "checkpoint_url=/The path of checkpoint in S3/" on the website UI interface. +# Add "run_distribute=True" on the website UI interface. +# Add "device_num = {number of the available devices}" on the website UI interface. +# Add other parameters you need on the website UI interface. +# (3) Set the code directory to "/path/PCB" on the website UI interface. +# (4) Set the startup file to "train.py" on the website UI interface. +# (5) Set the "Dataset path" and "Output file path" and "Job log path" to your path on the website UI interface. +# (6) Create your job. +``` + +### Result + +- Training PCB on Market-1501 + +```log +# standalone training result +epoch: 1 step: 202, loss is 28.947758 +epoch time: 88804.387 ms, per step time: 439.626 ms +epoch: 2 step: 202, loss is 18.160383 +epoch time: 35282.132 ms, per step time: 174.664 ms +epoch: 3 step: 202, loss is 14.728483 +epoch time: 35331.460 ms, per step time: 174.908 ms +... +``` + +- Training PCB on DukeMTMC-reID + +```log +# standalone training result +epoch: 1 step: 258, loss is 23.912783 +epoch time: 100480.371 ms, per step time: 389.459 ms +epoch: 2 step: 258, loss is 13.815624 +epoch time: 33952.824 ms, per step time: 131.600 ms +epoch: 3 step: 258, loss is 9.111069 +epoch time: 33952.491 ms, per step time: 131.599 ms +... +``` + +- Training PCB on CUHK03 + +```log +# standalone training result +epoch: 1 step: 115, loss is 34.977722 +epoch time: 87867.500 ms, per step time: 764.065 ms +epoch: 2 step: 115, loss is 24.710325 +epoch time: 15645.867 ms, per step time: 136.051 ms +epoch: 3 step: 115, loss is 16.847214 +epoch time: 15694.620 ms, per step time: 136.475 ms +... +``` + +- Training PCB+RPP on Market-1501 + +```log +# standalone training result +epoch: 1 step: 202, loss is 28.807777 +epoch time: 90390.587 ms, per step time: 447.478 ms +epoch: 2 step: 202, loss is 18.29936 +epoch time: 35274.752 ms, per step time: 174.627 ms +epoch: 3 step: 202, loss is 14.982595 +epoch time: 35277.650 ms, per step time: 174.642 ms +... +``` + +- Training PCB+RPP on DukeMTMC-reID + +```log +# standalone training result +epoch: 1 step: 258, loss is 23.096334 +epoch time: 96244.296 ms, per step time: 373.040 ms +epoch: 2 step: 258, loss is 13.114418 +epoch time: 33972.328 ms, per step time: 131.676 ms +epoch: 3 step: 258, loss is 8.97956 +epoch time: 33965.507 ms, per step time: 131.649 ms +... +``` + +- Training PCB+RPP on CUHK03 + +```log +# standalone training result +epoch: 1 step: 115, loss is 37.5888 +epoch time: 68445.567 ms, per step time: 595.179 ms +epoch: 2 step: 115, loss is 26.582499 +epoch time: 15640.461 ms, per step time: 136.004 ms +epoch: 3 step: 115, loss is 17.900295 +epoch time: 15637.023 ms, per step time: 135.974 ms +... +``` + +## Evaluation Process + +### Usage + +#### Running on Ascend + +```bash +# Usage: +bash run_eval.sh [MODEL_NAME] [DATASET_NAME] [DATASET_PATH] [CONFIG_PATH] [CHECKPOINT_PATH] [USE_G_FEATURE] +# MODEL_NAME should be in ['PCB', 'RPP'], DATASET_NAME should be in ['market', 'duke', 'cuhk03']. USE_G_FEATURE is a boolean parameter. If USE_G_FEATURE==True, G feature will be used for evaluation. If USE_G_FEATURE==False, H feature will be used for evaluation. + +# Examples: + +# 1. Evaluating PCB on Market-1501 using G feature + +bash run_eval.sh PCB market ../../Datasets/Market-1501 ../config/eval_PCB_market.yaml ./output/checkpoint/PCB/market/train/PCB-60_202.ckpt True + +# 2. Evaluating PCB on DukeMTMC-reID using G feature + +bash run_eval.sh PCB duke ../../Datasets/DukeMTMC-reID ../config/eval_PCB_duke.yaml ./output/checkpoint/PCB/duke/train/PCB-60_258.ckpt True + +# 3. Evaluating PCB on CUHK03 using G feature + +bash run_eval.sh PCB cuhk03 ../../Datasets/CUHK03 ../config/eval_PCB_cuhk03.yaml ./output/checkpoint/PCB/cuhk03/train/PCB_1-45_115.ckpt True + +# 4. Evaluating PCB+RPP on Market-1501 using G feature + +bash run_eval.sh RPP market ../../Datasets/Market-1501 ../config/eval_RPP_market.yaml ./output/checkpoint/RPP/market/train/RPP_1-10_202.ckpt True + +# 5. Evaluating PCB+RPP on DukeMTMC-reID using G feature + +bash run_eval.sh RPP duke ../../Datasets/DukeMTMC-reID ../config/eval_RPP_duke.yaml ./output/checkpoint/RPP/duke/train/RPP-40_258.ckpt True + +# 6. Evaluating PCB+RPP on CUHK03 using G feature + +bash run_eval.sh RPP cuhk03 ../../Datasets/CUHK03 ../config/eval_RPP_cuhk03.yaml ./output/checkpoint/RPP/cuhk03/train/RPP_1-10_115.ckpt True +``` + +Evaluation results will be stored in "output/log/{MODEL_NAME}/{DATASET_NAME}/eval". You can get metrics info in the log.txt. + +#### Modelarts Training Job + +If you want to run in modelarts, please check the official documentation of [modelarts](https://support.huaweicloud.com/modelarts/), and you can start standalone training and distributed training as follows: + +```text +# run evaluation on modelarts example +# (1) Add "config_path='/path_to_code/config/eval_PCB_market.yaml'" on the website UI interface. +# (2) Copy or upload your trained model to S3 bucket. +# (3) Perform a or b. +# a. Set "enable_modelarts=True" in yaml file. +# Set "checkpoint_file_path='/cache/load_checkpoint/model.ckpt" in yaml file. +# Set "checkpoint_url=/The path of checkpoint in S3/" in yaml file. +# Set "use_G_feature = True (False)" in yaml file. +# b. Add "enable_modelarts=True" on the website UI interface. +# Add "checkpoint_file_path='/cache/load_checkpoint/model.ckpt'" on the website UI interface. +# Add "checkpoint_url=/The path of checkpoint in S3/" on the website UI interface. +# Add "use_G_feature = True (False)" on the website UI interface. +# (4) Set the code directory to "/path/PCB" on the website UI interface. +# (5) Set the startup file to "eval.py" on the website UI interface. +# (6) Set the "Dataset path" and "Output file path" and "Job log path" to your path on the website UI interface. +# (7) Create your job. +``` + +### Result + +- Evaluating PCB on Market-1501 using G feature + +```log +Mean AP: 78.5% +CMC Scores market + top-1 93.0% + top-5 97.4% + top-10 98.4% +``` + +- Evaluating PCB on Market-1501 using H feature + +```log +Mean AP: 77.9% +CMC Scores market + top-1 93.0% + top-5 97.1% + top-10 98.1% +``` + +- Evaluating PCB on DukeMTMC-reID using G feature + +```log +Mean AP: 69.8% +CMC Scores duke + top-1 84.2% + top-5 92.4% + top-10 94.1% +``` + +- Evaluating PCB on DukeMTMC-reID using H feature + +```log +Mean AP: 68.6% +CMC Scores duke + top-1 84.2% + top-5 91.6% + top-10 93.9% +``` + +- Evaluating PCB on CUHK03 using G feature + +```log +Mean AP: 55.1% +CMC Scores cuhk03 + top-1 61.1% + top-5 79.5% + top-10 86.1% +``` + +- Evaluating PCB on CUHK03 using H feature + +```log +Mean AP: 55.4% +CMC Scores cuhk03 + top-1 61.9% + top-5 79.9% + top-10 85.9% +``` + +- Evaluating PCB+RPP on Market-1501 using G feature + +```log +Mean AP: 81.7% +CMC Scores market + top-1 93.8% + top-5 97.5% + top-10 98.6% +``` + +- Evaluating PCB+RPP on Market-1501 using H feature + +```log +Mean AP: 81.0% +CMC Scores market + top-1 93.6% + top-5 97.3% + top-10 98.5% +``` + +- Evaluating PCB+RPP on DukeMTMC-reID using G feature + +```log +Mean AP: 71.4% +CMC Scores duke + top-1 85.0% + top-5 92.6% + top-10 94.4% +``` + +- Evaluating PCB+RPP on DukeMTMC-reID using H feature + +```log +Mean AP: 70.2% +CMC Scores duke + top-1 85.1% + top-5 92.1% + top-10 94.0% +``` + +- Evaluating PCB+RPP on CUHK03 using G feature + +```log +Mean AP: 58.6% +CMC Scores cuhk03 + top-1 63.9% + top-5 81.2% + top-10 87.1% +``` + +- Evaluating PCB+RPP on CUHK03 using H feature + +```log +Mean AP: 59.1% +CMC Scores cuhk03 + top-1 65.0% + top-5 81.4% + top-10 86.9% +``` + +## Inference Process + +### Export MindIR + +Export MindIR on local + +```shell +python export.py --model_name [MODEL_NAME] --file_name [FILE_NAME] --file_format [FILE_FORMAT] --checkpoint_file_path [CKPT_PATH] --use_G_feature [USE_G_FEATURE] --config_path [CONFIG_PATH] +``` + +model_name should be in ["PCB", "RPP"]. +file_name refers to the name of the exported model. +file_format only supports "MINDIR". +checkpoint_file_path refers to the checkpoint to load. +USE_G_FEATURE is a boolean parameter. If USE_G_FEATURE==True, G feature will be used for evaluation. If USE_G_FEATURE==False, H feature will be used for evaluation. Different feature types will lead to different architectures of the exported model. +config_path refers to the path of infer_310_config.yaml. + +```shell +# Example: +# 1. Export PCB trained on Market-1501 using G feature +python export.py --model_name "PCB" --file_name "PCB_market_G" --file_format MINDIR --checkpoint_file_path ../PCB_market.ckpt --use_G_feature True --config_path ./config/infer_310_config.yaml +``` + +Export mindir on ModelArts + +```text +# (1) Add "config_path='/path_to_code/config/infer_310_config.yaml'" on the website UI interface. +# (2) Upload or copy your trained model to S3 bucket. +# (3) Perform a or b. +# a. Set "enable_modelarts=True" in infer_310_config.yaml +# Set "checkpoint_file_path='/cache/load_checkpoint/model.ckpt" in infer_310_config.yaml +# Set "checkpoint_url=/The path of checkpoint in S3/" in infer_310_config.yaml +# Set "model_name='PCB'" in infer_310_config.yaml +# Set "file_name='PCB_market_G'" in infer_310_config.yaml +# Set "file_format='MINDIR'" in infer_310_config.yaml +# Set "use_G_feature=True" in infer_310_config.yaml +# b. Add "enable_modelarts=True" on the website UI interface. +# Add "checkpoint_file_path='/cache/load_checkpoint/model.ckpt'" on the website UI interface. +# Add "checkpoint_url=/The path of checkpoint in S3/" on the website UI interface. +# Add "model_name='PCB'" on the website UI interface. +# Add "file_name='PCB_market_G'" on the website UI interface. +# Add "file_format='MINDIR'" on the website UI interface. +# Add "use_G_feature=True" on the website UI interface. +# (4) Set the code directory to "/path/PCB" on the website UI interface. +# (5) Set the startup file to "export.py" on the website UI interface. +# (6) Set "Output file path" and "Job log path" to your path on the website UI interface. +# (7) Create your job. +``` + +### Infer on Ascend310 + +Before performing inference, the mindir file must bu exported by `export.py` script. We only provide an example of inference using MINDIR model. +Current batch_Size can only be set to 1. + +```bash +# Ascend310 inference +bash run_infer_310.sh [MINDIR_PATH] [DATASET_NAME] [DATASET_PATH] [USE_G_FEATURE][CONFIG_PATH] [DEVICE_ID](optional) +``` + +- `DATASET_NAME` should be in [market, duke, cuhk03]. +- `USE_G_FEATURE` should be consistent with the export setting. +- `CONFIG_PATH` refers to the path of infer_310_config.yaml +- `DEVICE_ID` (optional), default 0. + +```bash +# Example: +# 1. Evaluating PCB on Market-1501 with G feature +bash run_infer_310.sh ../../mindir/PCB_market_G.mindir market ../../Datasets/Market-1501 True ../config/infer_310_config.yaml +``` + +### Result + +- Evaluating PCB on Market-1501 with G feature + +```log +Mean AP: 78.5% + top-1 93.1% + top-5 97.4% + top-10 98.4% +``` + +- Evaluating PCB on Market-1501 with H feature + +```log +Mean AP: 77.9% + top-1 92.9% + top-5 97.1% + top-10 98.1% +``` + +- Evaluating PCB on DukeMTMC-reID with G feature + +```log +Mean AP: 69.8% + top-1 84.2% + top-5 92.4% + top-10 94.1% +``` + +- Evaluating PCB on DukeMTMC-reID with H feature + +```log +Mean AP: 68.6% + top-1 84.2% + top-5 91.5% + top-10 93.9% +``` + +- Evaluating PCB on CUHK03 with G feature + +```log +Mean AP: 55.1% + top-1 60.9% + top-5 79.4% + top-10 86.1% +``` + +- Evaluating PCB on CUHK03 with H feature + +```log +Mean AP: 55.3% + top-1 61.7% + top-5 80.1% + top-10 86.0% +``` + +Inference results of PCB+RPP are not available as Ascend 310 currently doesn't support the AvgPool3D operator. + +# Model Description + +## Performance + +### Evaluation Performance + +#### PCB on Market-1501 + +| Parameter | Ascend 910 +| -------------------------- | -------------------------------------- +| Model | PCB +| Resource | Ascend 910; CPU 2.60GHz, 24 cores; Memory 96G; OS Euler2.8 +| MindSpore version | 1.3.0 +| Dataset | Market-1501 +| Training parameters | epoch=60, steps per epoch=202, batch_size = 64 +| Optimizer | SGD +| Loss function | Softmax Cross Entropy +| Output | Probability +| Loss | 0.05631405 +| Speed | 175 ms/step(1p) +| Total time | 37 min +| Parameters(M) | 27.2 + +#### PCB on DukeMTMC-reID + +| Parameter | Ascend 910 +| -------------------------- | -------------------------------------- +| Model | PCB +| Resource | Ascend 910; CPU 2.60GHz, 24 cores; Memory 96G; OS Euler2.8 +| MindSpore version | 1.3.0 +| Dataset | DukeMTMC-reID +| Training parameters | epoch=60, steps per epoch=258, batch_size = 64 +| Optimizer | SGD +| Loss function | Softmax Cross Entropy +| Output | Probability +| Loss | 0.095855206 +| Speed | 132 ms/step(1p) +| Total time | 36 min +| Parameters(M) | 27.2 + +#### PCB on CUHK03 + +| Parameter | Ascend 910 +| -------------------------- | -------------------------------------- +| Model | PCB +| Resource | Ascend 910; CPU 2.60GHz, 24 cores; Memory 96G; OS Euler2.8 +| MindSpore version | 1.3.0 +| Dataset | CUHK03 +| Training parameters | epoch=85, steps per epoch=115, batch_size = 64 +| Optimizer | SGD +| Loss function | Softmax Cross Entropy +| Output | Probability +| Loss | 0.094226934 +| Speed | 137 ms/step(1p) +| Total time | 25 min +| Parameters(M) | 27.2 + +#### PCB-RPP on Market-1501 + +| Parameter | Ascend 910 +| -------------------------- | -------------------------------------- +| Model | PCB-RPP +| Resource | Ascend 910; CPU 2.60GHz, 24 cores; Memory 96G; OS Euler2.8 +| MindSpore version | 1.3.0 +| Dataset | Market-1501 +| Training parameters | epoch=75, steps per epoch=202, batch_size = 64 +| Optimizer | SGD +| Loss function | Softmax Cross Entropy +| Output | Probability +| Loss | 0.04336106 +| Speed | 307 ms/step(1p) +| Total time | 72 min +| Parameters(M) | 27.2 + +#### PCB-RPP on DukeMTMC-reID + +| Parameter | Ascend 910 +| -------------------------- | -------------------------------------- +| Model | PCB-RPP +| Resource | Ascend 910; CPU 2.60GHz, 24 cores; Memory 96G; OS Euler2.8 +| MindSpore version | 1.3.0 +| Dataset | DukeMTMC-reID +| Training parameters | epoch=60, steps per epoch=258, batch_size = 64 +| Optimizer | SGD +| Loss function | Softmax Cross Entropy +| Output | Probability +| Loss | 0.03547495 +| Speed | 264 ms/step(1p) +| Total time | 59 min +| Parameters(M) | 27.2 + +#### PCB-RPP on CUHK03 + +| Parameter | Ascend 910 +| -------------------------- | -------------------------------------- +| Model | PCB-RPP +| Resource | Ascend 910; CPU 2.60GHz, 24 cores; Memory 96G; OS Euler2.8 +| MindSpore version | 1.3.0 +| Dataset | CUHK03 +| Training parameters | epoch=95, steps per epoch=115, batch_size = 64 +| Optimizer | SGD +| Loss function | Softmax Cross Entropy +| Output | Probability +| Loss | 0.083887264 +| Speed | 268 ms/step(1p) +| Total time | 59 min +| Parameters(M) | 27.2 + +# Description of Random Situation + +In dataset.py, we set the seed inside “create_dataset" function. We also use random seed in train.py. + +# ModelZoo Homepage + + Please check the official [homepage](https://gitee.com/mindspore/models). diff --git a/research/cv/pcb/README_CN.md b/research/cv/pcb/README_CN.md new file mode 100644 index 0000000000000000000000000000000000000000..df83c80ba7598697c473818bd4216edbf85d926e --- /dev/null +++ b/research/cv/pcb/README_CN.md @@ -0,0 +1,1007 @@ +# 目录 + +<!-- TOC --> + +- [目录](#目录) +- [PCB描述](#pcb描述) + - [概述](#概述) + - [论文](#论文) +- [模型架构](#模型架构) +- [数据集](#数据集) +- [特性](#特性) + - [混合精度](#混合精度) +- [环境要求](#环境要求) +- [快速入门](#快速入门) +- [脚本说明](#脚本说明) + - [脚本及样例代码](#脚本及样例代码) + - [脚本参数](#脚本参数) + - [训练过程](#训练过程) + - [用法](#用法) + - [Ascend处理器环境运行](#ascend处理器环境运行) + - [结果](#结果) + - [评估过程](#评估过程) + - [用法](#用法-1) + - [Ascend处理器环境运行](#ascend处理器环境运行-1) + - [结果](#结果-1) + - [推理过程](#推理过程) + - [导出MindIR](#导出mindir) + - [在Ascend310执行推理](#在ascend310执行推理) + - [结果](#结果-2) +- [模型描述](#模型描述) + - [性能](#性能) + - [评估性能](#评估性能) + - [Market-1501上的PCB](#market-1501上的pcb) + - [DukeMTMC-reID上的PCB](#dukemtmc-reid上的pcb) + - [CUHK03上的PCB](#cuhk03上的pcb) + - [Market-1501上的PCB-RPP](#market-1501上的pcb-rpp) + - [DukeMTMC-reID上的PCB-RPP](#dukemtmc-reid上的pcb-rpp) + - [CUHK03上的PCB-RPP](#cuhk03上的pcb-rpp) +- [随机情况说明](#随机情况说明) +- [ModelZoo主页](#modelzoo主页) + +<!-- /TOC --> + +# PCB描述 + +## 概述 + +PCB(Part-level Convolutional Baseline)模型是行人重识别任务的经典模型,它通过对输入图像进行均匀分划,构建出包含图像各部分特征的卷积描述子,用于后续行人检索。此外,原论文提出了RPP(Refined Part Pooling)方法对离群点所属区域进行重新分配,进一步提高了区域内特征的一致性,有效提升了PCB模型的精度。 + +如下为MindSpore使用Market-1501/DukeMTMC-reID/CUHK03数据集对PCB/PCB+RPP进行训练的示例。 + +## 论文 + +1. [论文](https://arxiv.org/pdf/1711.09349.pdf):Yifan Sun, Liang Zheng, Yi Yang, Qi Tian, Shengjin Wang."Beyond Part Models: Person Retrieval with Refined Part Pooling (and A Strong Convolutional Baseline)" + +# 模型架构 + +PCB的总体网络架构如下: +[链接](https://arxiv.org/pdf/1711.09349.pdf) + +# 数据集 + +使用的数据集:[Market-1501](<http://zheng-lab.cecs.anu.edu.au/Project/project_reid.html>) +[下载地址](https://pan.baidu.com/s/1qWEcLFQ?_at_=1640837580475) + +- 数据集组成: + - 训练集:包含751个行人的12936个RGB图像 + - 测试集: + + -query set: 包含750个行人的3368个RGB图像 + + -gallery set:包含751个行人的15913个RGB图像 + +- 数据格式:PNG图像 + - 注:数据在src/datasets/market.py中处理。 +- 下载数据集。目录结构如下: + +```text +├─ Market-1501 + │ + ├─bounding_box_test + │ + └─bounding_box_train + │ + └─gt_bbx + │ + └─gt_query + │ + └─query +``` + +使用的数据集:[DukeMTMC-reID](http://vision.cs.duke.edu/DukeMTMC/) +[下载地址](https://pan.baidu.com/share/init?surl=jS0XM7Var5nQGcbf9xUztw) 提取码:bhbh + +- 数据集组成: + - 训练集:包含702个行人的16522个RGB图像 + - 测试集: + + -query set: 包含702个行人的2228个RGB图像 + + -gallery set:包含1110个行人的17661个RGB图像 + +- 数据格式:PNG图像 + - 注:数据在src/datasets/duke.py中处理。 +- 下载数据集。目录结构如下: + +```text +├─ DukeMTMC-reID + │ + ├─bounding_box_test + │ + └─bounding_box_train + │ + └─query +``` + +使用的数据集:[CUHK03](<http://www.ee.cuhk.edu.hk/~xgwang/CUHK_identification.html>) +[下载地址](https://pan.baidu.com/s/1o8txURK) + +原论文在CUHK03上使用了新的 [测试协议](https://github.com/zhunzhong07/person-re-ranking/tree/master/CUHK03-NP) +新协议将原始的CUHK03数据集按照Market-1501数据集格式进行了划分 +[新协议下载地址](https://drive.google.com/file/d/0B7TOZKXmIjU3OUhfd3BPaVRHZVE/view?resourcekey=0-hU4gyE6hFsBgizIh9DFqtA) + +- 新协议下CUHK03数据集组成: + - 训练集:包含767个行人的7365个RGB图像 + - 测试集: + + -query set: 包含700个行人的1400个RGB图像 + + -gallery set:包含700个行人的5332个RGB图像 + +- 数据格式:PNG图像 + - 注:数据在src/datasets/cuhk03.py中处理。 + +- 下载数据集。 + +需要先分别下载原始数据集与新协议划分文件,然后将原始数据集中的cuhk03.mat文件与新协议中的cuhk03_new_protocol_config_detected.mat文件放在同一文件夹(CUHK03)下: + +```text +├─ CUHK03 + │ + ├─ cuhk03.mat + │ + └─ cuhk03_new_protocol_config_detected.mat +``` + +- 预训练的Resnet50权重 [下载地址](https://gitee.com/starseekerX/PCB_pretrained_checkpoint/blob/master/pretrained_resnet50.ckpt) + +# 特性 + +## 混合精度 + +采用[混合精度](https://www.mindspore.cn/docs/programming_guide/zh-CN/r1.6/enable_mixed_precision.html)的训练方法使用支持单精度和半精度数据来提高深度学习神经网络的训练速度,同时保持单精度训练所能达到的网络精度。混合精度训练提高计算速度、减少内存使用的同时,支持在特定硬件上训练更大的模型或实现更大批次的训练。 +以FP16算子为例,如果输入数据类型为FP32,MindSpore后台会自动降低精度来处理数据。用户可打开INFO日志,搜索“reduce precision”查看精度降低的算子。 + +# 环境要求 + +- 硬件(Ascend) + - 准备Ascend910处理器搭建硬件环境。 +- 框架 + - [MindSpore](https://www.mindspore.cn/install/en) +- 如需查看详情,请参见如下资源: + - [MindSpore教程](https://www.mindspore.cn/tutorials/zh-CN/master/index.html) + - [MindSpore Python API](https://www.mindspore.cn/docs/api/zh-CN/master/index.html) + +# 快速入门 + +通过官方网站安装MindSpore后,您可以按照如下步骤进行训练和评估: + +> - <font size=2>训练、评估和推理时,请按以下方式使用数据集:如果使用Market-1501数据集, DATASET_PATH={Market-1501目录所在路径};如果使用Duke-MTMC-reID数据集, DATASET_PATH={Duke-MTMC-reID目录所在路径};如果使用CUHK03数据集, DATASET_PATH={CUHK03目录所在路径}</font> + +- Ascend处理器环境运行 + +```bash +# 单机训练 +# 用法: +bash run_standalone_train.sh [MODEL_NAME] [DATASET_NAME] [DATASET_PATH] [CONFIG_PATH] [PRETRAINED_CKPT_PATH](可选) + +# 例如: +bash run_standalone_train.sh PCB market ../../Datasets/Market-1501 ../config/train_PCB_market.yaml ../../pretrained_resnet50.ckpt + +# 分布式训练(以PCB模型在Market上训练为例) +# 用法: +bash run_distribute_train.sh [RANK_TABLE_FILE] [MODEL_NAME] [DATASET_NAME] [DATASET_PATH] [CONFIG_PATH] [PRETRAINED_CKPT_PATH](可选) + +# 例如: +bash run_distribute_train.sh ../hccl_8p_01234567_127.0.0.1.json PCB market ../../Datasets/Market-1501 ../config/train_PCB_market.yaml ../../pretrained_resnet50.ckpt + +# 运行评估示例(以PCB模型在Market上评估为例) +# 用法: +bash run_eval.sh [MODEL_NAME] [DATASET_NAME] [DATASET_PATH] [CONFIG_PATH] [CHECKPOINT_PATH] [USE_G_FEATURE] + +# 例如: +bash run_eval.sh PCB market ../../Datasets/Market-1501 ../config/eval_PCB_market.yaml ./output/checkpoint/PCB/market/train/PCB-60_202.ckpt True +``` + +# 脚本说明 + +## 脚本及样例代码 + +```text +. +└──PCB + ├── README.md + ├── config # 参数配置 + ├── base_config.yaml + ├── train_PCB_market.yaml + ├── train_PCB_duke.yaml + ├── train_PCB_cuhk03 # PCB在CUHK03数据集上训练包含训练与微调两个阶段,因此需要两个配置文件 + ├── train_PCB.yaml + ├── finetune_PCB.yaml + ├── train_RPP_market # PCB+RPP在Market-1501数据集上训练需要先训练PCB,然后将PCB权重载入PCB+RPP续训,因此需要两个配置文件 + ├── train_PCB.yaml + ├── train_RPP.yaml + ├── train_RPP_duke + ├── train_PCB.yaml + ├── train_RPP.yaml + ├── train_RPP_cuhk03 + ├── train_PCB.yaml + ├── train_RPP.yaml + ├── finetune_RPP.yaml + ├── eval_PCB_market.yaml # 评估PCB在Market-1501数据集上的精度 + ├── eval_PCB_duke.yaml + ├── eval_PCB_cuhk03.yaml + ├── eval_RPP_market.yaml # 评估PCB+RPP在Market-1501数据集上的精度 + ├── eval_RPP_duke.yaml + ├── eval_RPP_cuhk03.yaml + ├── infer_310_config.yaml # 用于模型导出成mindir、310推理的配置文件 + ├── scripts + ├── run_standalone_train.sh # 启动单卡训练脚本 + ├── run_distribute_eval.sh # 启动八卡训练脚本 + ├── run_eval.sh # 启动评估脚本 + ├── run_infer_310.sh # 启动310推理 + ├── src + ├── dataset.py # 数据预处理 + ├── eval_callback.py # 训练时推理回调函数 + ├── eval_utils.py # 评估mAP、CMC所需的util函数 + ├── meter.py + ├── logging.py # 日志管理程序 + ├── lr_generator.py # 生成每个步骤的学习率 + ├── pcb.py # PCB模型结构、损失函数 + ├── rpp.py # PCB+RPP模型结构 + ├── resnet.py # resnet50模型结构 + ├── datasets # 包含处理Market-1501、DukeMTMC-reID、CUHK03数据集的程序 + ├── market.py # 处理Market-1501的程序 + ├── duke.py # 处理DukeMTMC-reID的程序 + ├── cuhk03.py # 处理CUHK03的程序 + ├── model_utils + ├── config.py # 参数配置 + ├── device_adapter.py # 设备配置 + ├── local_adapter.py # 本地设备配置 + └── moxing_adapter.py # modelarts设备配置 + ├── eval.py # 评估网络 + └── train.py # 训练网络 + └── export.py # 模型导出 + └── preprocess.py # 310推理预处理 + └── postprocess.py # 310推理后处理 +``` + +## 脚本参数 + +在配置文件中可以配置训练、评估、模型导出、推理参数,下面以PCB在Market-1501数据集上的训练、评估,模型导出与推理为例。 + +- 配置PCB在Market-1501数据集训练。 + +```text +enable_modelarts: False # 是否开启modelarts云上训练作业训练 +data_url: "" +train_url: "" +checkpoint_url: "" +run_distribute: False # 是否开启分布式训练 +enable_profiling: False +dataset_path: "/cache/dataset/" # 数据集路径 +output_path: "/cache/output/" # 结果输出路径 +load_path: "/cache/load_checkpoint/" +device_target: "Ascend" +log_save_path: "./log/PCB/market/train" # 日志保存路径 +checkpoint_save_path: "./checkpoint/PCB/market/train" # 断点保存路径 +checkpoint_file_path: "/cache/load_checkpoint/pretrained_resnet50.ckpt" # 断点加载路径 + +mindrecord_dir: "./MindRecord" # MindRecord文件保存路径 +dataset_name: "market" # 数据集简名 +batch_size: 64 # 一个数据批次大小 +num_parallel_workers: 4 +device_num: 1 # 设备数量 + +model_name: "PCB" # 模型名 +learning_rate: 0.1 # 学习率 +lr_mult: 0.1 # 主干网络学习率倍数 +decay_rate: 0.1 # 学习率衰减率 +momentum: 0.9 # SGD优化器的动量 +weight_decay: 5e-4 # SGD优化器的权重衰减率 +nesterov: True + +mode_name: "GRAPH" # 程序运行模式 +sink_mode: True # 是否开启数据下沉 +seed: 37 # 随机种子 +epoch_size: 60 # 训练回合数 +decay_epoch_size: 40 # 学习率衰减的回合数 +warmup_epoch_size: 1 # 训练开始的warmup回合数 + +save_checkpoint: True # 是否保存断点 +save_checkpoint_epochs: 60 # 保存断点的回合数 +keep_checkpoint_max: 15 # 最多保存的断点数 + +run_eval: False # 是否在训练时进行评估 +eval_interval: 15 # 评估的回合间隔 +eval_start_epoch: 60 # 评估的开始回合 +use_G_feature: True # 评估时是否使用G feature,若不使用则代表使用H feature +``` + +- 配置PCB在Market-1501数据集评估。 + +```text +enable_modelarts: False # 是否开启modelarts云上训练作业训练 +data_url: "" +train_url: "" +checkpoint_url: "" +enable_profiling: False +dataset_path: "/cache/dataset/" # 数据集路径 +output_path: "/cache/output/" # 结果输出路径 +load_path: "/cache/load_checkpoint/" +device_target: "Ascend" +log_save_path: "./log/PCB/market/eval" # 日志保存路径 +checkpoint_file_path: "/cache/load_checkpoint/PCB-60_202.ckpt" # 断点加载路径 + +mindrecord_dir: "./MindRecord" # MindRecord文件保存路径 +dataset_name: "market" # 数据集简名 +batch_size: 64 # 一个数据批次大小 +num_parallel_workers: 4 + +model_name: "PCB" # 模型名 +use_G_feature: True # 评估时是否使用G feature,若不使用则代表使用H feature +``` + +- 配置PCB模型导出与推理。 + +```text +enable_modelarts: False # 是否开启modelarts云上训练作业训练 +data_url: "" +train_url: "" +checkpoint_url: "" +enable_profiling: False +dataset_path: "/cache/dataset/" # 数据集路径 +output_path: "/cache/output/" # 结果输出路径 +load_path: "/cache/load_checkpoint/" +device_target: "Ascend" +checkpoint_file_path: "/cache/load_checkpoint/PCB-60_202.ckpt" # 断点加载路径 +batch_size: 1 # 目前仅支持batch size为1的推理 +model_name: "PCB" # 模型名 +use_G_feature: True # 模型导出时是否使用G feature,若不使用则代表使用H feature,G/H feature选择的差异会影响导出模型的结构 + +device_id: 0 +image_height: 384 # 导出模型输入的高 +image_width: 128 # 导出模型输入的宽 +file_name: "export_PCB_market_G" # 导出的模型名 +file_format: "MINDIR" # 导出的模型格式 + +preprocess_result_path: "./preprocess_Result" #310推理预处理结果路径 + +query_prediction_path: "./query_result_files" #query集合10推理结果输出路径 +gallery_prediction_path: "./gallery_result_files" #gallery集合310推理结果输出路径 +``` + +## 训练过程 + +### 用法 + +#### Ascend处理器环境运行 + +```bash +# 单机训练 +# 用法: +bash run_standalone_train.sh [MODEL_NAME] [DATASET_NAME] [DATASET_PATH] [CONFIG_PATH] [PRETRAINED_CKPT_PATH](可选) +# 其中MODEL_NAME可从['PCB', 'RPP']中选择,DATASET_NAME可从['market', 'duke', 'cuhk03']中选择。 + +# 请注意数据集与配置文件需与训练脚本对应,请见下面的示例 + +# 示例: + +# 1、PCB在Market-1501上训练 + +bash run_standalone_train.sh PCB market ../../Datasets/Market-1501 ../config/train_PCB_market.yaml ../../pretrained_resnet50.ckpt + +# 2、PCB在DukeMTMC-reID上训练 + +bash run_standalone_train.sh PCB duke ../../Datasets/DukeMTMC-reID ../config/train_PCB_duke.yaml ../../pretrained_resnet50.ckpt + +# 3、PCB在CUHK03上训练(由于训练涉及多个配置文件,因此在这里CONFIG_PATH传入配置文件所在目录路径即可) + +bash run_standalone_train.sh PCB cuhk03 ../../Datasets/CUHK03 ../config/train_PCB_cuhk03 ../../pretrained_resnet50.ckpt + +# 4、PCB+RPP在Market-1501上训练(由于训练涉及多个配置文件,因此在这里CONFIG_PATH传入配置文件所在目录路径即可) + +bash run_standalone_train.sh RPP market ../../Datasets/Market-1501 ../config/train_RPP_market ../../pretrained_resnet50.ckpt + +# 5、PCB+RPP在DukeMTMC-reID上训练(由于训练涉及多个配置文件,因此在这里CONFIG_PATH传入配置文件所在目录路径即可) + +bash run_standalone_train.sh RPP duke ../../Datasets/DukeMTMC-reID ../config/train_RPP_duke ../../pretrained_resnet50.ckpt + +# 6、PCB+RPP在CUHK03上训练(由于训练涉及多个配置文件,因此在这里CONFIG_PATH传入配置文件所在目录路径即可) + +bash run_standalone_train.sh RPP cuhk03 ../../Datasets/CUHK03 ../config/train_RPP_cuhk03 ../../pretrained_resnet50.ckpt + + +# 分布式训练 +# 用法: +bash run_distribute_train.sh [RANK_TABLE_FILE] [MODEL_NAME] [DATASET_NAME] [DATASET_PATH] [CONFIG_PATH] [PRETRAINED_CKPT_PATH](可选) + +# 其中MODEL_NAME可从['PCB', 'RPP']中选择,DATASET_NAME可从['market', 'duke', 'cuhk03']中选择。 + +# 请注意数据集与配置文件需与训练脚本对应,请见下面的示例 + +# 示例 + +# 1、PCB在Market-1501上分布式训练(Ascend 8卡) + +bash run_distribute_train.sh ../hccl_8p_01234567_127.0.0.1.json PCB market ../../Datasets/Market-1501 ../config/train_PCB_market.yaml ../../pretrained_resnet50.ckpt + +# 2、PCB在DukeMTMC-reID上分布式训练(Ascend 8卡) + +bash run_distribute_train.sh ../hccl_8p_01234567_127.0.0.1.json PCB duke ../../Datasets/DukeMTMC-reID ../config/train_PCB_duke.yaml ../../pretrained_resnet50.ckpt + +# 3、PCB在CUHK03上分布式训练(Ascend 8卡) + +bash run_distribute_train.sh ../hccl_8p_01234567_127.0.0.1.json PCB cuhk03 ../../Datasets/CUHK03 ../config/train_PCB_cuhk03 ../../pretrained_resnet50.ckpt + +# 4、RPP在Market-1501上分布式训练(Ascend 8卡) + +bash run_distribute_train.sh ../hccl_8p_01234567_127.0.0.1.json RPP market ../../Datasets/Market-1501 ../config/train_RPP_market ../../pretrained_resnet50.ckpt + +# 5、RPP在DukeMTMC-reID上分布式训练(Ascend 8卡) + +bash run_distribute_train.sh ../hccl_8p_01234567_127.0.0.1.json RPP duke ../../Datasets/DukeMTMC-reID ../config/train_RPP_duke ../../pretrained_resnet50.ckpt + +# 6、RPP在CUHK03上分布式训练(Ascend 8卡) + +bash run_distribute_train.sh ../hccl_8p_01234567_127.0.0.1.json RPP cuhk03 ../../Datasets/CUHK03 ../config/train_RPP_cuhk03 ../../pretrained_resnet50.ckpt +``` + +分布式训练需要提前创建JSON格式的HCCL配置文件。 + +具体操作,参见[hccl_tools](https://gitee.com/mindspore/models/tree/master/utils/hccl_tools)中的说明。 + +训练结果保存在脚本目录的output文件夹下,其中日志文件保存在./output/log/{MODEL_NAME}/{DATASET_NAME}/train下,断点文件保存在./output/checkpoint/{MODEL_NAME}/{DATASET_NAME}/train下,您可以在其中找到所需的信息。 + +#### Modelarts训练作业 + +如果要在modelarts上进行模型的训练,可以参考modelarts的官方指导文档(https://support.huaweicloud.com/modelarts/) +开始进行模型的训练和推理,具体操作如下: + +```text +# 在modelarts上进行单卡训练的示例: +# (1) 在网页上设置 "config_path='/path_to_code/config/train_PCB_market.yaml'" +# (2) 选择a或者b其中一种方式。 +# a. 在yaml文件中设置 "enable_modelarts=True" 。 +# 设置 "checkpoint_file_path='/cache/load_checkpoint/model.ckpt" 在 yaml 文件. +# 设置 "checkpoint_url=/The path of checkpoint in S3/" 在 yaml 文件. +# 如需自定义参数,可在yaml文件中设置其它网络所需的参数。 +# b. 增加 "enable_modelarts=True" 参数在modearts的界面上。 +# 增加 "checkpoint_file_path='/cache/load_checkpoint/model.ckpt'" 参数在modearts的界面上。 +# 增加 "checkpoint_url=/The path of checkpoint in S3/" 参数在modearts的界面上。 +# 如需自定义参数,可在modelarts的界面上设置其它网络所需的参数。 +# +# (3) 在modelarts的界面上设置代码的路径 "/path/PCB"。 +# (4) 在modelarts的界面上设置模型的启动文件 "train.py" 。 +# (5) 在modelarts的界面上设置模型的数据路径 "Dataset path" , +# 模型的输出路径"Output file path" 和模型的日志路径 "Job log path" 。 +# (6) 开始模型的训练。 + +# 在modelarts上进行分布式训练的示例: +# (1) 在网页上设置 "config_path='/path_to_code/config/train_PCB_market.yaml'" +# (2) 选择a或者b其中一种方式。 +# a. 在yaml文件中设置 "enable_modelarts=True" 。 +# 设置 "checkpoint_file_path='/cache/load_checkpoint/model.ckpt" 在 yaml 文件. +# 设置 "checkpoint_url=/The path of checkpoint in S3/" 在 yaml 文件. +# 设置 "run_distribute=True" 在 yaml 文件. +# 设置 "device_num = {可用的卡数}" 在 yaml 文件. +# 如需自定义参数,可在yaml文件中设置其它网络所需的参数。 +# b. 增加 "enable_modelarts=True" 参数在modearts的界面上。 +# 增加 "checkpoint_file_path='/cache/load_checkpoint/model.ckpt'" 参数在modearts的界面上。 +# 增加 "checkpoint_url=/The path of checkpoint in S3/" 参数在modearts的界面上。 +# 增加 "run_distribute=True" 参数在modearts的界面上。 +# 增加 "device_num = {可用的卡数}" 参数在modearts的界面上。 +# 如需自定义参数,可在modelarts的界面上设置其它网络所需的参数。 +# (3) 在modelarts的界面上设置代码的路径 "/path/PCB"。 +# (4) 在modelarts的界面上设置模型的启动文件 "train.py" 。 +# (5) 在modelarts的界面上设置模型的数据路径 "Dataset path" , 断点路径 “checkpoint file path” , +# 模型的输出路径"Output file path" 和模型的日志路径 "Job log path" 。 +# (6) 开始模型的训练。 +``` + +### 结果 + +- 使用Market-1501数据集训练PCB + +```log +# 单卡训练结果 +epoch: 1 step: 202, loss is 28.947758 +epoch time: 88804.387 ms, per step time: 439.626 ms +epoch: 2 step: 202, loss is 18.160383 +epoch time: 35282.132 ms, per step time: 174.664 ms +epoch: 3 step: 202, loss is 14.728483 +epoch time: 35331.460 ms, per step time: 174.908 ms +... +``` + +- 使用DukeMTMC-reID数据集训练PCB + +```log +# 单卡训练结果 +epoch: 1 step: 258, loss is 23.912783 +epoch time: 100480.371 ms, per step time: 389.459 ms +epoch: 2 step: 258, loss is 13.815624 +epoch time: 33952.824 ms, per step time: 131.600 ms +epoch: 3 step: 258, loss is 9.111069 +epoch time: 33952.491 ms, per step time: 131.599 ms +... +``` + +- 使用CUHK03数据集训练PCB + +```log +# 单卡训练结果 +epoch: 1 step: 115, loss is 34.977722 +epoch time: 87867.500 ms, per step time: 764.065 ms +epoch: 2 step: 115, loss is 24.710325 +epoch time: 15645.867 ms, per step time: 136.051 ms +epoch: 3 step: 115, loss is 16.847214 +epoch time: 15694.620 ms, per step time: 136.475 ms +... +``` + +- 使用Market-1501数据集训练RPP + +```log +# 单卡训练结果 +epoch: 1 step: 202, loss is 28.807777 +epoch time: 90390.587 ms, per step time: 447.478 ms +epoch: 2 step: 202, loss is 18.29936 +epoch time: 35274.752 ms, per step time: 174.627 ms +epoch: 3 step: 202, loss is 14.982595 +epoch time: 35277.650 ms, per step time: 174.642 ms +... +``` + +- 使用DukeMTMC-reID数据集训练RPP + +```log +# 单卡训练结果 +epoch: 1 step: 258, loss is 23.096334 +epoch time: 96244.296 ms, per step time: 373.040 ms +epoch: 2 step: 258, loss is 13.114418 +epoch time: 33972.328 ms, per step time: 131.676 ms +epoch: 3 step: 258, loss is 8.97956 +epoch time: 33965.507 ms, per step time: 131.649 ms +... +``` + +- 使用CUHK03数据集训练RPP + +```log +# 单卡训练结果 +epoch: 1 step: 115, loss is 37.5888 +epoch time: 68445.567 ms, per step time: 595.179 ms +epoch: 2 step: 115, loss is 26.582499 +epoch time: 15640.461 ms, per step time: 136.004 ms +epoch: 3 step: 115, loss is 17.900295 +epoch time: 15637.023 ms, per step time: 135.974 ms +... +``` + +## 评估过程 + +### 用法 + +#### Ascend处理器环境运行 + +```bash +# 用法: +bash run_eval.sh [MODEL_NAME] [DATASET_NAME] [DATASET_PATH] [CONFIG_PATH] [CHECKPOINT_PATH] [USE_G_FEATURE] + +# 其中MODEL_NAME可从['PCB', 'RPP']中选择,DATASET_NAME可从['market', 'duke', 'cuhk03']中选择, USE_G_FEATURE表示评估时是否使用论文中的G feature,如果不使用,则表示使用H feature。 + +# 请注意数据集与配置文件需与训练脚本对应,请见下面的示例 + +# 示例: + +# 1、PCB在Market-1501上使用G feature评估 + +bash run_eval.sh PCB market ../../Datasets/Market-1501 ../config/eval_PCB_market.yaml ./output/checkpoint/PCB/market/train/PCB-60_202.ckpt True + +# 2、PCB在DukeMTMC-reID上使用G feature评估 + +bash run_eval.sh PCB duke ../../Datasets/DukeMTMC-reID ../config/eval_PCB_duke.yaml ./output/checkpoint/PCB/duke/train/PCB-60_258.ckpt True + +# 3、PCB在CUHK03上使用G feature评估(由于训练涉及多个配置文件,因此在这里CONFIG_PATH传入配置文件所在目录路径即可) + +bash run_eval.sh PCB cuhk03 ../../Datasets/CUHK03 ../config/eval_PCB_cuhk03.yaml ./output/checkpoint/PCB/cuhk03/train/PCB_1-45_115.ckpt True + +# 4、PCB+RPP在Market-1501上使用G feature评估(由于训练涉及多个配置文件,因此在这里CONFIG_PATH传入配置文件所在目录路径即可) + +bash run_eval.sh RPP market ../../Datasets/Market-1501 ../config/eval_RPP_market.yaml ./output/checkpoint/RPP/market/train/RPP_1-10_202.ckpt True + +# 5、PCB+RPP在DukeMTMC-reID上使用G feature评估(由于训练涉及多个配置文件,因此在这里CONFIG_PATH传入配置文件所在目录路径即可) + +bash run_eval.sh RPP duke ../../Datasets/DukeMTMC-reID ../config/eval_RPP_duke.yaml ./output/checkpoint/RPP/duke/train/RPP-40_258.ckpt True + +# 6、PCB+RPP在CUHK03上使用G feature评估(由于训练涉及多个配置文件,因此在这里CONFIG_PATH传入配置文件所在目录路径即可) + +bash run_eval.sh RPP cuhk03 ../../Datasets/CUHK03 ../config/eval_RPP_cuhk03.yaml ./output/checkpoint/RPP/cuhk03/train/RPP_1-10_115.ckpt True +``` + +评估结果保存在脚本目录的output/log/{MODEL_NAME}/{DATASET_NAME}/eval中。 + +#### Modelarts训练作业 + +如果要在modelarts上进行模型的训练,可以参考modelarts的官方指导文档(https://support.huaweicloud.com/modelarts/) +开始进行模型的训练和推理,具体操作如下: + +```text +# 在modelarts上进行模型评估的示例 +# (1) 在网页上设置 "config_path='/path_to_code/config/eval_PCB_market.yaml'" +# (2) 把训练好的模型放到桶的对应位置。 +# (3) 选择a或者b其中一种方式。 +# a. 设置 "enable_modelarts=True" 在 yaml 文件. +# 设置 "checkpoint_file_path='/cache/load_checkpoint/model.ckpt" 在 yaml 文件. +# 设置 "checkpoint_url=/The path of checkpoint in S3/" 在 yaml 文件. +# 设置 "use_G_feature = True (False)" 在 yaml 文件. +# b. 增加 "enable_modelarts=True" 参数在modearts的界面上。 +# 增加 "checkpoint_file_path='/cache/load_checkpoint/model.ckpt'" 参数在modearts的界面上。 +# 增加 "checkpoint_url=/The path of checkpoint in S3/" 参数在modearts的界面上。 +# 增加 "use_G_feature = True (False)" 参数在modearts的界面上。 +# (4) 在modelarts的界面上设置代码的路径 "/path/PCB"。 +# (5) 在modelarts的界面上设置模型的启动文件 "eval.py" 。 +# (6) 在modelarts的界面上设置模型的数据路径 "Dataset path" , +# 模型的输出路径"Output file path" 和模型的日志路径 "Job log path" 。 +# (7) 开始模型的评估。 +``` + +### 结果 + +- PCB在Market-1501数据集使用G feature进行评估 + +```log +Mean AP: 78.5% +CMC Scores market + top-1 93.0% + top-5 97.4% + top-10 98.4% +``` + +- PCB在Market-1501数据集使用H feature进行评估 + +```log +Mean AP: 77.9% +CMC Scores market + top-1 93.0% + top-5 97.1% + top-10 98.1% +``` + +- PCB在DukeMTMC-reID数据集使用G feature进行评估 + +```log +Mean AP: 69.8% +CMC Scores duke + top-1 84.2% + top-5 92.4% + top-10 94.1% +``` + +- PCB在DukeMTMC-reID数据集使用H feature进行评估 + +```log +Mean AP: 68.6% +CMC Scores duke + top-1 84.2% + top-5 91.6% + top-10 93.9% +``` + +- PCB在CUHK03数据集使用G feature进行评估 + +```log +Mean AP: 55.1% +CMC Scores cuhk03 + top-1 61.1% + top-5 79.5% + top-10 86.1% +``` + +- PCB在CUHK03数据集使用H feature进行评估 + +```log +Mean AP: 55.4% +CMC Scores cuhk03 + top-1 61.9% + top-5 79.9% + top-10 85.9% +``` + +- RPP在Market-1501数据集使用G feature进行评估 + +```log +Mean AP: 81.7% +CMC Scores market + top-1 93.8% + top-5 97.5% + top-10 98.6% +``` + +- RPP在Market-1501数据集使用H feature进行评估 + +```log +Mean AP: 81.0% +CMC Scores market + top-1 93.6% + top-5 97.3% + top-10 98.5% +``` + +- RPP在DukeMTMC-reID数据集使用G feature进行评估 + +```log +Mean AP: 71.4% +CMC Scores duke + top-1 85.0% + top-5 92.6% + top-10 94.4% +``` + +- RPP在DukeMTMC-reID数据集使用H feature进行评估 + +```log +Mean AP: 70.2% +CMC Scores duke + top-1 85.1% + top-5 92.1% + top-10 94.0% +``` + +- RPP在CUHK03数据集使用G feature进行评估 + +```log +Mean AP: 58.6% +CMC Scores cuhk03 + top-1 63.9% + top-5 81.2% + top-10 87.1% +``` + +- RPP在CUHK03数据集使用H feature进行评估 + +```log +Mean AP: 59.1% +CMC Scores cuhk03 + top-1 65.0% + top-5 81.4% + top-10 86.9% +``` + +## 推理过程 + +### 导出MindIR + +导出mindir模型 + +```shell +python export.py --model_name [MODEL_NAME] --file_name [FILE_NAME] --file_format [FILE_FORMAT] --checkpoint_file_path [CKPT_PATH] --use_G_feature [USE_G_FEATURE] --config_path [CONFIG_PATH] +``` + +参数model_name可从["PCB","RPP"]中选择。 +参数file_name为导出的模型名称。 +参数file_format 仅支持 "MINDIR"。 +参数checkpoint_file_path为断点路径。 +参数use_G_feature表示导出模型是否使用G feature,若不使用,则使用H feature。 feature类型的不同对应导出模型的结构也会不同。 +参数config_path表示infer_310_config.yaml的路径 + +```shell +# 示例: +# 1、导出在Market-1501上训练后使用G feature的PCB模型。 +python export.py --model_name "PCB" --file_name "PCB_market_G" --file_format MINDIR --checkpoint_file_path ../PCB_market.ckpt --use_G_feature True --config_path ./config/infer_310_config.yaml +``` + +ModelArts导出mindir + +```text +# (1) 在网页上设置 "config_path='/path_to_code/config/infer_310_config.yaml'" +# (2) 把训练好的模型地方到桶的对应位置。 +# (3) 选择a或者b其中一种方式。 +# a. 设置 "enable_modelarts=True" +# 设置 "checkpoint_file_path='/cache/load_checkpoint/model.ckpt" 在 yaml 文件。 +# 设置 "checkpoint_url=/The path of checkpoint in S3/" 在 yaml 文件。 +# 设置 "model_name='PCB'" 在 yaml 文件。 +# 设置 "file_name='PCB_market_G'"参数在yaml文件。 +# 设置 "file_format='MINDIR'" 参数在yaml文件。 +# 设置 "use_G_feature=True" 参数在 yaml 文件。 +# b. 增加 "enable_modelarts=True" 参数在modearts的界面上。 +# 增加 "checkpoint_file_path='/cache/load_checkpoint/model.ckpt'" 参数在modearts的界面上。 +# 增加 "checkpoint_url=/The path of checkpoint in S3/" 参数在modearts的界面上。 +# 设置 "model_name='PCB'"参数在modearts的界面上。 +# 设置 "file_name='PCB_market_G'"参数在modearts的界面上。 +# 设置 "file_format='MINDIR'" 参数在modearts的界面上。 +# 设置 "use_G_feature=True"参数在modearts的界面上。 +# (4) 在modelarts的界面上设置代码的路径 "/path/PCB"。 +# (5) 在modelarts的界面上设置模型的启动文件 "export.py" 。 +# (6) 在modelarts的界面上设置模型的输出路径"Output file path" 和模型的日志路径 "Job log path" 。 +# (7) 开始导出mindir。 +``` + +### 在Ascend310执行推理 + +在执行推理前,mindir文件必须通过`export.py`脚本导出。以下展示了使用minir模型执行推理的示例。 +目前仅支持batch_Size为1的推理。 + +```bash +# Ascend310 inference +bash run_infer_310.sh [MINDIR_PATH] [DATASET_NAME] [DATASET_PATH] [USE_G_FEATURE][CONFIG_PATH] [DEVICE_ID](optional) +``` + +- `DATASET_NAME` 选择范围:[market, duke, cuhk03]。 +- `USE_G_FEATURE` 应与模型导出时的选项一致 +- `CONFIG_PATH` 表示infer_310_config.yaml的路径 +- `DEVICE_ID` 可选,默认值为0。 + +```bash +# 示例: +# 1、PCB在Market-1501上使用G feature进行推理。 +bash run_infer_310.sh ../../mindir/PCB_market_G.mindir market ../../Datasets/Market-1501 True ../config/infer_310_config.yaml +``` + +### 结果 + +推理结果保存在脚本执行的当前路径,你可以在metrics.log中看到以下精度计算结果。 + +- PCB在Market-1501数据集使用G feature进行推理 + +```log +Mean AP: 78.5% + top-1 93.1% + top-5 97.4% + top-10 98.4% +``` + +- PCB在Market-1501数据集使用H feature进行推理 + +```log +Mean AP: 77.9% + top-1 92.9% + top-5 97.1% + top-10 98.1% +``` + +- PCB在DukeMTMC-reID数据集使用G feature进行推理 + +```log +Mean AP: 69.8% + top-1 84.2% + top-5 92.4% + top-10 94.1% +``` + +- PCB在DukeMTMC-reID数据集使用H feature进行推理 + +```log +Mean AP: 68.6% + top-1 84.2% + top-5 91.5% + top-10 93.9% +``` + +- PCB在CUHK03数据集使用G feature进行推理 + +```log +Mean AP: 55.1% + top-1 60.9% + top-5 79.4% + top-10 86.1% +``` + +- PCB在CUHK03数据集使用H feature进行推理 + +```log +Mean AP: 55.3% + top-1 61.7% + top-5 80.1% + top-10 86.0% +``` + +由于PCB+RPP模型含有AvgPool3D算子,该算子在Ascend310环境暂不支持,因此这一部分未进行推理。 + +# 模型描述 + +## 性能 + +### 评估性能 + +#### Market-1501上的PCB + +| 参数 | Ascend 910 +| -------------------------- | -------------------------------------- +| 模型版本 | PCB +| 资源 | Ascend 910;CPU 2.60GHz,24核;内存 96G;系统 Euler2.8 +| MindSpore版本 | 1.3.0 +| 数据集 | Market-1501 +| 训练参数 | epoch=60, steps per epoch=202, batch_size = 64 +| 优化器 | SGD +| 损失函数 | Softmax交叉熵 +| 输出 | 概率 +| 损失 | 0.05631405 +| 速度 | 175毫秒/步(1卡) +| 总时长 | 37分钟 +| 参数(M) | 27.2 + +#### DukeMTMC-reID上的PCB + +| 参数 | Ascend 910 +| -------------------------- | -------------------------------------- +| 模型版本 | PCB +| 资源 | Ascend 910;CPU 2.60GHz,24核;内存 96G;系统 Euler2.8 +| MindSpore版本 | 1.3.0 +| 数据集 | DukeMTMC-reID +| 训练参数 | epoch=60, steps per epoch=258, batch_size = 64 +| 优化器 | SGD +| 损失函数 | Softmax交叉熵 +| 输出 | 概率 +| 损失 | 0.095855206 +| 速度 | 132毫秒/步(1卡) +| 总时长 | 36分钟 +| 参数(M) | 27.2 + +#### CUHK03上的PCB + +| 参数 | Ascend 910 +| -------------------------- | -------------------------------------- +| 模型版本 | PCB +| 资源 | Ascend 910;CPU 2.60GHz,24核;内存 96G;系统 Euler2.8 +| MindSpore版本 | 1.3.0 +| 数据集 | CUHK03 +| 训练参数 | epoch=85, steps per epoch=115, batch_size = 64 +| 优化器 | SGD +| 损失函数 | Softmax交叉熵 +| 输出 | 概率 +| 损失 | 0.094226934 +| 速度 | 137毫秒/步(1卡) +| 总时长 | 25分钟 +| 参数(M) | 27.2 + +#### Market-1501上的PCB-RPP + +| 参数 | Ascend 910 +| -------------------------- | -------------------------------------- +| 模型版本 | PCB-RPP +| 资源 | Ascend 910;CPU 2.60GHz,24核;内存 96G;系统 Euler2.8 +| MindSpore版本 | 1.3.0 +| 数据集 | Market-1501 +| 训练参数 | epoch=75, steps per epoch=202, batch_size = 64 +| 优化器 | SGD +| 损失函数 | Softmax交叉熵 +| 输出 | 概率 +| 损失 | 0.04336106 +| 速度 | 307毫秒/步(1卡) +| 总时长 | 72分钟 +| 参数(M) | 27.2 + +#### DukeMTMC-reID上的PCB-RPP + +| 参数 | Ascend 910 +| -------------------------- | -------------------------------------- +| 模型版本 | PCB-RPP +| 资源 | Ascend 910;CPU 2.60GHz,24核;内存 96G;系统 Euler2.8 +| MindSpore版本 | 1.3.0 +| 数据集 | DukeMTMC-reID +| 训练参数 | epoch=60, steps per epoch=258, batch_size = 64 +| 优化器 | SGD +| 损失函数 | Softmax交叉熵 +| 输出 | 概率 +| 损失 | 0.03547495 +| 速度 | 264毫秒/步(1卡) +| 总时长 | 59分钟 +| 参数(M) | 27.2 + +#### CUHK03上的PCB-RPP + +| 参数 | Ascend 910 +| -------------------------- | -------------------------------------- +| 模型版本 | PCB-RPP +| 资源 | Ascend 910;CPU 2.60GHz,24核;内存 96G;系统 Euler2.8 +| MindSpore版本 | 1.3.0 +| 数据集 | CUHK03 +| 训练参数 | epoch=95, steps per epoch=115, batch_size = 64 +| 优化器 | SGD +| 损失函数 | Softmax交叉熵 +| 输出 | 概率 +| 损失 | 0.083887264 +| 速度 | 268毫秒/步(1卡) +| 总时长 | 59分钟 +| 参数(M) | 27.2 + +# 随机情况说明 + +`dataset.py`中设置了“create_dataset”函数内的种子,同时还使用了train.py中的随机种子。 + +# ModelZoo主页 + + 请浏览官网[主页](https://gitee.com/mindspore/models)。 diff --git a/research/cv/pcb/ascend310_infer/CMakeLists.txt b/research/cv/pcb/ascend310_infer/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..ee3c85447340e0449ff2b70ed24f60a17e07b2b6 --- /dev/null +++ b/research/cv/pcb/ascend310_infer/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.14.1) +project(Ascend310Infer) +add_compile_definitions(_GLIBCXX_USE_CXX11_ABI=0) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -g -std=c++17 -Werror -Wall -fPIE -Wl,--allow-shlib-undefined") +set(PROJECT_SRC_ROOT ${CMAKE_CURRENT_LIST_DIR}/) +option(MINDSPORE_PATH "mindspore install path" "") +include_directories(${MINDSPORE_PATH}) +include_directories(${MINDSPORE_PATH}/include) +include_directories(${PROJECT_SRC_ROOT}) +find_library(MS_LIB libmindspore.so ${MINDSPORE_PATH}/lib) +file(GLOB_RECURSE MD_LIB ${MINDSPORE_PATH}/_c_dataengine*) + +add_executable(main src/main.cc src/utils.cc) +target_link_libraries(main ${MS_LIB} ${MD_LIB} gflags) diff --git a/research/cv/pcb/ascend310_infer/build.sh b/research/cv/pcb/ascend310_infer/build.sh new file mode 100644 index 0000000000000000000000000000000000000000..d8b0bae914799f0effc0360fe0b0e47d0bed51cc --- /dev/null +++ b/research/cv/pcb/ascend310_infer/build.sh @@ -0,0 +1,24 @@ +#!/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. +# ============================================================================ + + +if [ ! -d out ]; then + mkdir out +fi +cd out || exit +cmake .. \ + -DMINDSPORE_PATH="`pip show mindspore-ascend | grep Location | awk '{print $2"/mindspore"}' | xargs realpath`" +make diff --git a/research/cv/pcb/ascend310_infer/inc/utils.h b/research/cv/pcb/ascend310_infer/inc/utils.h new file mode 100644 index 0000000000000000000000000000000000000000..06c5753535e59f6058fd969d4da33797baa12487 --- /dev/null +++ b/research/cv/pcb/ascend310_infer/inc/utils.h @@ -0,0 +1,34 @@ +/** + * 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 MINDSPORE_INFERENCE_UTILS_H_ +#define MINDSPORE_INFERENCE_UTILS_H_ + +#include <sys/stat.h> +#include <dirent.h> +#include <vector> +#include <string> +#include <memory> +#include "include/api/types.h" + +DIR *OpenDir(std::string_view dirName); +std::string RealPath(std::string_view path); +mindspore::MSTensor ReadFileToTensor(const std::string &file); +int WriteResult(const std::string&, const std::vector<mindspore::MSTensor>&, const std::string&); +std::vector<std::string> GetAllFiles(std::string_view dir_name); + +#endif diff --git a/research/cv/pcb/ascend310_infer/src/main.cc b/research/cv/pcb/ascend310_infer/src/main.cc new file mode 100644 index 0000000000000000000000000000000000000000..cb8ecc790cc57887133539dd4962f82d519799f7 --- /dev/null +++ b/research/cv/pcb/ascend310_infer/src/main.cc @@ -0,0 +1,158 @@ +/** + * 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 <sys/time.h> +#include <gflags/gflags.h> +#include <dirent.h> +#include <iostream> +#include <string> +#include <algorithm> +#include <iosfwd> +#include <vector> +#include <fstream> +#include <sstream> + +#include "include/api/model.h" +#include "include/api/context.h" +#include "include/api/types.h" +#include "include/api/serialization.h" +#include "include/dataset/vision_ascend.h" +#include "include/dataset/execute.h" +#include "include/dataset/transforms.h" +#include "include/dataset/vision.h" +#include "inc/utils.h" + +using mindspore::dataset::vision::Decode; +using mindspore::dataset::vision::Resize; +using mindspore::dataset::vision::CenterCrop; +using mindspore::dataset::vision::Normalize; +using mindspore::dataset::vision::HWC2CHW; +using mindspore::dataset::TensorTransform; +using mindspore::Context; +using mindspore::Serialization; +using mindspore::Model; +using mindspore::Status; +using mindspore::ModelType; +using mindspore::GraphCell; +using mindspore::kSuccess; +using mindspore::MSTensor; +using mindspore::dataset::Execute; + +DEFINE_string(mindir_path, "", "mindir path"); +DEFINE_string(query_image_path, "", "query image path"); +DEFINE_string(gallery_image_path, "", "gallery image path"); +DEFINE_int32(device_id, 0, "device id"); + + +int main(int argc, char **argv) { + gflags::ParseCommandLineFlags(&argc, &argv, true); + if (RealPath(FLAGS_mindir_path).empty()) { + std::cout << "Invalid mindir" << std::endl; + return 1; + } + auto context = std::make_shared<Context>(); + auto ascend310 = std::make_shared<mindspore::Ascend310DeviceInfo>(); + ascend310->SetDeviceID(FLAGS_device_id); + context->MutableDeviceInfo().push_back(ascend310); + mindspore::Graph graph; + Serialization::Load(FLAGS_mindir_path, ModelType::kMindIR, &graph); + Model model; + Status ret = model.Build(GraphCell(graph), context); + if (ret != kSuccess) { + std::cout << "ERROR: Build failed." << std::endl; + return 1; + } + auto query_image_files = GetAllFiles(FLAGS_query_image_path); + if (query_image_files.empty()) { + std::cout << "ERROR: no query data." << std::endl; + return 1; + } + auto gallery_image_files = GetAllFiles(FLAGS_gallery_image_path); + if (gallery_image_files.empty()) { + std::cout << "ERROR: no gallery data." << std::endl; + return 1; + } + std::vector<MSTensor> modelInputs = model.GetInputs(); + std::map<double, double> costTime_map; + size_t query_size = query_image_files.size(); + size_t gallery_size = gallery_image_files.size(); + std::string query_saveDir = "./query_result_files"; + std::string gallery_saveDir = "./gallery_result_files"; + for (size_t i = 0; i < query_size; ++i) { + struct timeval start = {0}; + struct timeval end = {0}; + double startTimeMs; + double endTimeMs; + std::vector<MSTensor> inputs; + std::vector<MSTensor> outputs; + std::cout << "Start processing query image files:" << query_image_files[i] <<std::endl; + MSTensor image = ReadFileToTensor(query_image_files[i]); + inputs.emplace_back(modelInputs[0].Name(), modelInputs[0].DataType(), modelInputs[0].Shape(), + image.Data().get(), image.DataSize()); + gettimeofday(&start, nullptr); + ret = model.Predict(inputs, &outputs); + gettimeofday(&end, nullptr); + if (ret != kSuccess) { + std::cout << "Process " << query_image_files[i] << " failed." << std::endl; + return 1; + } + startTimeMs = (1.0 * start.tv_sec * 1000000 + start.tv_usec) / 1000; + endTimeMs = (1.0 * end.tv_sec * 1000000 + end.tv_usec) / 1000; + costTime_map.insert(std::pair<double, double>(startTimeMs, endTimeMs)); + WriteResult(query_image_files[i], outputs, query_saveDir); + } + for (size_t i = 0; i < gallery_size; ++i) { + struct timeval start = {0}; + struct timeval end = {0}; + double startTimeMs; + double endTimeMs; + std::vector<MSTensor> inputs; + std::vector<MSTensor> outputs; + std::cout << "Start processing gallery files:" << gallery_image_files[i] <<std::endl; + MSTensor image = ReadFileToTensor(gallery_image_files[i]); + inputs.emplace_back(modelInputs[0].Name(), modelInputs[0].DataType(), modelInputs[0].Shape(), + image.Data().get(), image.DataSize()); + gettimeofday(&start, nullptr); + ret = model.Predict(inputs, &outputs); + gettimeofday(&end, nullptr); + if (ret != kSuccess) { + std::cout << "Process " << gallery_image_files[i] << " failed." << std::endl; + return 1; + } + startTimeMs = (1.0 * start.tv_sec * 1000000 + start.tv_usec) / 1000; + endTimeMs = (1.0 * end.tv_sec * 1000000 + end.tv_usec) / 1000; + costTime_map.insert(std::pair<double, double>(startTimeMs, endTimeMs)); + WriteResult(gallery_image_files[i], outputs, gallery_saveDir); + } + double average = 0.0; + int inferCount = 0; + for (auto iter = costTime_map.begin(); iter != costTime_map.end(); iter++) { + average += iter->second - iter->first; + inferCount++; + } + average = average / inferCount; + std::stringstream timeCost; + timeCost << "NN inference cost average time: "<< average << " ms of infer_count " << inferCount << std::endl; + std::cout << "NN inference cost average time: "<< average << "ms of infer_count " << inferCount << std::endl; + std::string fileName = "./time_Result" + std::string("/test_perform_static.txt"); + std::ofstream fileStream(fileName.c_str(), std::ios::trunc); + fileStream << timeCost.str(); + fileStream.close(); + costTime_map.clear(); + return 0; +} + diff --git a/research/cv/pcb/ascend310_infer/src/utils.cc b/research/cv/pcb/ascend310_infer/src/utils.cc new file mode 100644 index 0000000000000000000000000000000000000000..fba4abcecff30264a48c6e26e13c10b6019120be --- /dev/null +++ b/research/cv/pcb/ascend310_infer/src/utils.cc @@ -0,0 +1,131 @@ +/** + * 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 <fstream> +#include <algorithm> +#include <iostream> +#include "inc/utils.h" + +using mindspore::MSTensor; +using mindspore::DataType; + +std::vector<std::string> GetAllFiles(std::string_view dirName) { + struct dirent *filename; + DIR *dir = OpenDir(dirName); + if (dir == nullptr) { + return {}; + } + std::vector<std::string> res; + while ((filename = readdir(dir)) != nullptr) { + std::string dName = std::string(filename->d_name); + if (dName == "." || dName == ".." || filename->d_type != DT_REG) { + continue; + } + res.emplace_back(std::string(dirName) + "/" + filename->d_name); + } + std::sort(res.begin(), res.end()); + for (auto &f : res) { + std::cout << "image file: " << f << std::endl; + } + return res; +} + + +mindspore::MSTensor ReadFileToTensor(const std::string &file) { + if (file.empty()) { + std::cout << "Pointer file is nullptr" << std::endl; + return mindspore::MSTensor(); + } + + std::ifstream ifs(file); + if (!ifs.good()) { + std::cout << "File: " << file << " is not exist" << std::endl; + return mindspore::MSTensor(); + } + + if (!ifs.is_open()) { + std::cout << "File: " << file << "open failed" << std::endl; + return mindspore::MSTensor(); + } + + ifs.seekg(0, std::ios::end); + size_t size = ifs.tellg(); + mindspore::MSTensor buffer(file, mindspore::DataType::kNumberTypeUInt8, {static_cast<int64_t>(size)}, nullptr, size); + + ifs.seekg(0, std::ios::beg); + ifs.read(reinterpret_cast<char *>(buffer.MutableData()), size); + ifs.close(); + + return buffer; +} + +int WriteResult(const std::string& imageFile, const std::vector<MSTensor> &outputs, const std::string& saveDir) { + for (size_t i = 0; i < outputs.size(); ++i) { + size_t outputSize; + std::shared_ptr<const void> netOutput; + netOutput = outputs[i].Data(); + outputSize = outputs[i].DataSize(); + int pos = imageFile.rfind('/'); + std::string fileName(imageFile, pos + 1); + fileName.replace(fileName.find('.'), fileName.size() - fileName.find('.'), ".bin"); + std::string outFileName = saveDir + "/" + fileName; + FILE *outputFile = fopen(outFileName.c_str(), "wb"); + fwrite(netOutput.get(), outputSize, sizeof(char), outputFile); + fclose(outputFile); + outputFile = nullptr; + } + return 0; +} + + +DIR *OpenDir(std::string_view dirName) { + if (dirName.empty()) { + std::cout << " dirName is null ! " << std::endl; + return nullptr; + } + std::string realPath = RealPath(dirName); + struct stat s; + lstat(realPath.c_str(), &s); + if (!S_ISDIR(s.st_mode)) { + std::cout << "dirName is not a valid directory !" << std::endl; + return nullptr; + } + DIR *dir; + dir = opendir(realPath.c_str()); + if (dir == nullptr) { + std::cout << "Can not open dir " << dirName << std::endl; + return nullptr; + } + std::cout << "Successfully opened the dir " << dirName << std::endl; + return dir; +} + + +std::string RealPath(std::string_view path) { + char realPathMem[PATH_MAX] = {0}; + char *realPathRet = nullptr; + realPathRet = realpath(path.data(), realPathMem); + if (realPathRet == nullptr) { + std::cout << "File: " << path << " is not exist."; + return ""; + } + + std::string realPath(realPathMem); + std::cout << path << " realpath is: " << realPath << std::endl; + return realPath; +} diff --git a/research/cv/pcb/config/base_config.yaml b/research/cv/pcb/config/base_config.yaml new file mode 100644 index 0000000000000000000000000000000000000000..dfa7e6609a9d1c4ad6a2d8513e917a4f021fb418 --- /dev/null +++ b/research/cv/pcb/config/base_config.yaml @@ -0,0 +1,70 @@ +# Builtin Configurations(DO NOT CHANGE THESE CONFIGURATIONS unless you know exactly what you are doing) + +enable_modelarts: False +# Url for modelarts +data_url: "" +train_url: "" +checkpoint_url: "" +# Path for local +run_distribute: False +enable_profiling: False +dataset_path: "/cache/dataset/" +output_path: "/cache/output/" +load_path: "/cache/load_checkpoint/" +device_target: "Ascend" +log_save_path: "./log/" +checkpoint_save_path: "./checkpoint/" +checkpoint_file_path: "/cache/load_checkpoint/pretrained_resnet50.ckpt" +# ========================================================================= + +# dataset setting +mindrecord_dir: "./MindRecord" +dataset_name: "cuhk03" +batch_size: 1 +num_parallel_workers: 4 +device_num: 1 + +# model setting +model_name: "PCB" + +# optimizer setting +learning_rate: 0.1 +lr_mult: 0.1 +decay_rate: 0.1 +momentum: 0.9 +weight_decay: 5e-4 +nesterov: True + +# training setting +mode_name: "GRAPH" +sink_mode: True +seed: 1 +epoch_size: 10 +decay_epoch_size: 10 +warmup_epoch_size: 0 + +# checkpoint callbacks setting +save_checkpoint: True +save_checkpoint_epochs: 10 +keep_checkpoint_max: 15 + +# EvalCallBack setting +run_eval: False +eval_interval: 15 +eval_start_epoch: 60 + +use_G_feature: True + +# Export setting +device_id: 0 +image_height: 384 +image_width: 128 +file_name: "export_PCB_test" +file_format: "MINDIR" + +# preprocess setting +preprocess_result_path: "./preprocess_Result" + +# postprocessing setting +query_prediction_path: "./query_result_files" +gallery_prediction_path: "./gallery_result_files" diff --git a/research/cv/pcb/config/eval_PCB_cuhk03.yaml b/research/cv/pcb/config/eval_PCB_cuhk03.yaml new file mode 100644 index 0000000000000000000000000000000000000000..a8f85617d9b4ee8ae3b1a384c4991320d94a3693 --- /dev/null +++ b/research/cv/pcb/config/eval_PCB_cuhk03.yaml @@ -0,0 +1,28 @@ +# Builtin Configurations(DO NOT CHANGE THESE CONFIGURATIONS unless you know exactly what you are doing) + +enable_modelarts: False +# Url for modelarts +data_url: "" +train_url: "" +checkpoint_url: "" +# Path for local +run_distribute: False +enable_profiling: False +dataset_path: "/cache/dataset/" +output_path: "/cache/output/" +load_path: "/cache/load_checkpoint/" +device_target: "Ascend" +log_save_path: "./log/PCB/cuhk03/eval/" +checkpoint_save_path: "" +checkpoint_file_path: "/cache/load_checkpoint/PCB-45_115.ckpt" +# ========================================================================= + +# dataset setting +mindrecord_dir: "./MindRecord" +dataset_name: "cuhk03" +batch_size: 64 +num_parallel_workers: 4 + +# model setting +model_name: "PCB" +use_G_feature: True diff --git a/research/cv/pcb/config/eval_PCB_duke.yaml b/research/cv/pcb/config/eval_PCB_duke.yaml new file mode 100644 index 0000000000000000000000000000000000000000..831bebfd6359c63ad764ad38169c8f5ef6778c81 --- /dev/null +++ b/research/cv/pcb/config/eval_PCB_duke.yaml @@ -0,0 +1,28 @@ +# Builtin Configurations(DO NOT CHANGE THESE CONFIGURATIONS unless you know exactly what you are doing) + +enable_modelarts: False +# Url for modelarts +data_url: "" +train_url: "" +checkpoint_url: "" +# Path for local +run_distribute: False +enable_profiling: False +dataset_path: "/cache/dataset/" +output_path: "/cache/output/" +load_path: "/cache/load_checkpoint/" +device_target: "Ascend" +log_save_path: "./log/PCB/duke/eval/" +checkpoint_save_path: "" +checkpoint_file_path: "/cache/load_checkpoint/PCB-60_258.ckpt" +# ========================================================================= + +# dataset setting +mindrecord_dir: "./MindRecord" +dataset_name: "duke" +batch_size: 64 +num_parallel_workers: 4 + +# model setting +model_name: "PCB" +use_G_feature: True diff --git a/research/cv/pcb/config/eval_PCB_market.yaml b/research/cv/pcb/config/eval_PCB_market.yaml new file mode 100644 index 0000000000000000000000000000000000000000..53786d72539e40929734ceeb8743e1ecbfad7ee4 --- /dev/null +++ b/research/cv/pcb/config/eval_PCB_market.yaml @@ -0,0 +1,28 @@ +# Builtin Configurations(DO NOT CHANGE THESE CONFIGURATIONS unless you know exactly what you are doing) + +enable_modelarts: False +# Url for modelarts +data_url: "" +train_url: "" +checkpoint_url: "" +# Path for local +run_distribute: False +enable_profiling: False +dataset_path: "/cache/dataset/" +output_path: "/cache/output/" +load_path: "/cache/load_checkpoint/" +device_target: "Ascend" +log_save_path: "./log/PCB/market/eval/" +checkpoint_save_path: "" +checkpoint_file_path: "/cache/load_checkpoint/PCB-60_202.ckpt" +# ========================================================================= + +# dataset setting +mindrecord_dir: "./MindRecord" +dataset_name: "market" +batch_size: 64 +num_parallel_workers: 4 + +# model setting +model_name: "PCB" +use_G_feature: True diff --git a/research/cv/pcb/config/eval_RPP_cuhk03.yaml b/research/cv/pcb/config/eval_RPP_cuhk03.yaml new file mode 100644 index 0000000000000000000000000000000000000000..3851874cdaea814671c6e0676cdf93d95846d733 --- /dev/null +++ b/research/cv/pcb/config/eval_RPP_cuhk03.yaml @@ -0,0 +1,28 @@ +# Builtin Configurations(DO NOT CHANGE THESE CONFIGURATIONS unless you know exactly what you are doing) + +enable_modelarts: False +# Url for modelarts +data_url: "" +train_url: "" +checkpoint_url: "" +# Path for local +run_distribute: False +enable_profiling: False +dataset_path: "/cache/dataset/" +output_path: "/cache/output/" +load_path: "/cache/load_checkpoint/" +device_target: "Ascend" +log_save_path: "./log/RPP/cuhk03/eval/" +checkpoint_save_path: "" +checkpoint_file_path: "/cache/load_checkpoint/RPP-10_115.ckpt" +# ========================================================================= + +# dataset setting +mindrecord_dir: "./MindRecord" +dataset_name: "cuhk03" +batch_size: 64 +num_parallel_workers: 4 + +# model setting +model_name: "RPP" +use_G_feature: True diff --git a/research/cv/pcb/config/eval_RPP_duke.yaml b/research/cv/pcb/config/eval_RPP_duke.yaml new file mode 100644 index 0000000000000000000000000000000000000000..b4777d2aa8eba059193c74beb9c11a683e4d220d --- /dev/null +++ b/research/cv/pcb/config/eval_RPP_duke.yaml @@ -0,0 +1,28 @@ +# Builtin Configurations(DO NOT CHANGE THESE CONFIGURATIONS unless you know exactly what you are doing) + +enable_modelarts: False +# Url for modelarts +data_url: "" +train_url: "" +checkpoint_url: "" +# Path for local +run_distribute: False +enable_profiling: False +dataset_path: "/cache/dataset/" +output_path: "/cache/output/" +load_path: "/cache/load_checkpoint/" +device_target: "Ascend" +log_save_path: "./log/RPP/duke/eval/" +checkpoint_save_path: "" +checkpoint_file_path: "/cache/load_checkpoint/RPP-40_258.ckpt" +# ========================================================================= + +# dataset setting +mindrecord_dir: "./MindRecord" +dataset_name: "duke" +batch_size: 64 +num_parallel_workers: 4 + +# model setting +model_name: "RPP" +use_G_feature: True diff --git a/research/cv/pcb/config/eval_RPP_market.yaml b/research/cv/pcb/config/eval_RPP_market.yaml new file mode 100644 index 0000000000000000000000000000000000000000..bb0475d37e3671faddcb6b7c11d56f757a947813 --- /dev/null +++ b/research/cv/pcb/config/eval_RPP_market.yaml @@ -0,0 +1,28 @@ +# Builtin Configurations(DO NOT CHANGE THESE CONFIGURATIONS unless you know exactly what you are doing) + +enable_modelarts: False +# Url for modelarts +data_url: "" +train_url: "" +checkpoint_url: "" +# Path for local +run_distribute: False +enable_profiling: False +dataset_path: "/cache/dataset/" +output_path: "/cache/output/" +load_path: "/cache/load_checkpoint/" +device_target: "Ascend" +log_save_path: "./log/RPP/market/eval/" +checkpoint_save_path: "" +checkpoint_file_path: "/cache/load_checkpoint/RPP-10_202.ckpt" +# ========================================================================= + +# dataset setting +mindrecord_dir: "./MindRecord" +dataset_name: "market" +batch_size: 64 +num_parallel_workers: 4 + +# model setting +model_name: "RPP" +use_G_feature: True diff --git a/research/cv/pcb/config/infer_310_config.yaml b/research/cv/pcb/config/infer_310_config.yaml new file mode 100644 index 0000000000000000000000000000000000000000..fbd910d64f00aa7c646c9b3fb0267fc45f408946 --- /dev/null +++ b/research/cv/pcb/config/infer_310_config.yaml @@ -0,0 +1,41 @@ +# Builtin Configurations(DO NOT CHANGE THESE CONFIGURATIONS unless you know exactly what you are doing) + +enable_modelarts: False +# Url for modelarts +data_url: "" +train_url: "" +checkpoint_url: "" +# Path for local +run_distribute: False +enable_profiling: False +dataset_path: "/cache/dataset/" +output_path: "/cache/output/" +load_path: "/cache/load_checkpoint/" +device_target: "Ascend" +log_save_path: "./log/" +checkpoint_save_path: "./checkpoint/" +checkpoint_file_path: "/cache/load_checkpoint/RPP-10_115.ckpt" +# ========================================================================= + +# dataset setting +mindrecord_dir: "./MindRecord" +dataset_name: "cuhk03" +batch_size: 1 +num_parallel_workers: 4 + +# model setting +model_name: "RPP" +use_G_feature: True + +# Export setting +image_height: 384 +image_width: 128 +file_name: "export_RPP_cuhk03_G" +file_format: "MINDIR" + +# preprocess setting +preprocess_result_path: "./preprocess_Result" + +# postprocessing setting +query_prediction_path: "./query_result_files" +gallery_prediction_path: "./gallery_result_files" diff --git a/research/cv/pcb/config/train_PCB_cuhk03/finetune_PCB.yaml b/research/cv/pcb/config/train_PCB_cuhk03/finetune_PCB.yaml new file mode 100644 index 0000000000000000000000000000000000000000..3f338c032d39279907a5d1d7f0253c998fa6a809 --- /dev/null +++ b/research/cv/pcb/config/train_PCB_cuhk03/finetune_PCB.yaml @@ -0,0 +1,57 @@ +# Builtin Configurations(DO NOT CHANGE THESE CONFIGURATIONS unless you know exactly what you are doing) + +enable_modelarts: False +# Url for modelarts +data_url: "" +train_url: "" +checkpoint_url: "" +# Path for local +run_distribute: False +enable_profiling: False +dataset_path: "/cache/dataset/" +output_path: "/cache/output/" +load_path: "/cache/load_checkpoint/" +device_target: "Ascend" +log_save_path: "./log/PCB/cuhk03/train" +checkpoint_save_path: "./checkpoint/PCB/cuhk03/train" +checkpoint_file_path: "/cache/load_checkpoint/PCB-40_115.ckpt" +# ========================================================================= + +# dataset setting +mindrecord_dir: "./MindRecord" +dataset_name: "cuhk03" +batch_size: 64 +num_parallel_workers: 4 +device_num: 1 + +# model setting +model_name: "PCB" + +# optimizer setting +learning_rate: 0.05 +lr_mult: 0.1 +decay_rate: 0.5 +momentum: 0.9 +weight_decay: 5e-4 +nesterov: True +loss_scale: 1.0 + +# training setting +mode_name: "GRAPH" +sink_mode: True +seed: 1 +epoch_size: 45 +decay_epoch_size: 15 +warmup_epoch_size: 0 + +# checkpoint callbacks setting +save_checkpoint: True +save_checkpoint_epochs: 45 +keep_checkpoint_max: 15 + +# EvalCallBack setting +run_eval: False +eval_interval: 15 +eval_start_epoch: 60 + +use_G_feature: True diff --git a/research/cv/pcb/config/train_PCB_cuhk03/train_PCB.yaml b/research/cv/pcb/config/train_PCB_cuhk03/train_PCB.yaml new file mode 100644 index 0000000000000000000000000000000000000000..f4da8da515ea46d78e1fcbe6dc3c95164ea2940b --- /dev/null +++ b/research/cv/pcb/config/train_PCB_cuhk03/train_PCB.yaml @@ -0,0 +1,57 @@ +# Builtin Configurations(DO NOT CHANGE THESE CONFIGURATIONS unless you know exactly what you are doing) + +enable_modelarts: False +# Url for modelarts +data_url: "" +train_url: "" +checkpoint_url: "" +# Path for local +run_distribute: False +enable_profiling: False +dataset_path: "/cache/dataset/" +output_path: "/cache/output/" +load_path: "/cache/load_checkpoint/" +device_target: "Ascend" +log_save_path: "./log/PCB/cuhk03/train" +checkpoint_save_path: "./checkpoint/PCB/cuhk03/train" +checkpoint_file_path: "/cache/load_checkpoint/pretrained_resnet50.ckpt" +# ========================================================================= + +# dataset setting +mindrecord_dir: "./MindRecord" +dataset_name: "cuhk03" +batch_size: 64 +num_parallel_workers: 4 +device_num: 1 + +# model setting +model_name: "PCB" + +# optimizer setting +learning_rate: 0.1 +lr_mult: 0.1 +decay_rate: 0.1 +momentum: 0.9 +weight_decay: 5e-4 +nesterov: True +loss_scale: 1.0 + +# training setting +mode_name: "GRAPH" +sink_mode: True +seed: 1 +epoch_size: 40 +decay_epoch_size: 40 +warmup_epoch_size: 0 + +# checkpoint callbacks setting +save_checkpoint: True +save_checkpoint_epochs: 40 +keep_checkpoint_max: 15 + +# EvalCallBack setting +run_eval: False +eval_interval: 15 +eval_start_epoch: 60 + +use_G_feature: True diff --git a/research/cv/pcb/config/train_PCB_duke.yaml b/research/cv/pcb/config/train_PCB_duke.yaml new file mode 100644 index 0000000000000000000000000000000000000000..fac3137283fa883f3252a6efb654e55ad271f06e --- /dev/null +++ b/research/cv/pcb/config/train_PCB_duke.yaml @@ -0,0 +1,58 @@ +# Builtin Configurations(DO NOT CHANGE THESE CONFIGURATIONS unless you know exactly what you are doing) + +enable_modelarts: False +# Url for modelarts +data_url: "" +train_url: "" +checkpoint_url: "" +# Path for local +run_distribute: False +enable_profiling: False +dataset_path: "/cache/dataset/" +output_path: "/cache/output/" +load_path: "/cache/load_checkpoint/" +device_target: "Ascend" + +log_save_path: "./log/PCB/duke/train" +checkpoint_save_path: "./checkpoint/PCB/duke/train" +checkpoint_file_path: "/cache/load_checkpoint/pretrained_resnet50.ckpt" +# ========================================================================= + +# dataset setting +mindrecord_dir: "./MindRecord" +dataset_name: "duke" +batch_size: 64 +num_parallel_workers: 4 +device_num: 1 + +# model setting +model_name: "PCB" + +# optimizer setting +learning_rate: 0.1 +lr_mult: 0.1 +decay_rate: 0.1 +momentum: 0.9 +weight_decay: 5e-4 +nesterov: True +loss_scale: 1.0 + +# training setting +mode_name: "GRAPH" +sink_mode: True +seed: 1 +epoch_size: 60 +decay_epoch_size: 40 +warmup_epoch_size: 0 + +# checkpoint callbacks setting +save_checkpoint: True +save_checkpoint_epochs: 60 +keep_checkpoint_max: 15 + +# EvalCallBack setting +run_eval: False +eval_interval: 15 +eval_start_epoch: 60 + +use_G_feature: True diff --git a/research/cv/pcb/config/train_PCB_market.yaml b/research/cv/pcb/config/train_PCB_market.yaml new file mode 100644 index 0000000000000000000000000000000000000000..f77013df505ebbdbe4f5d75df2367a2fbadd8679 --- /dev/null +++ b/research/cv/pcb/config/train_PCB_market.yaml @@ -0,0 +1,58 @@ +# Builtin Configurations(DO NOT CHANGE THESE CONFIGURATIONS unless you know exactly what you are doing) + +enable_modelarts: False +# Url for modelarts +data_url: "" +train_url: "" +checkpoint_url: "" +# Path for local +run_distribute: False +enable_profiling: False +dataset_path: "/cache/dataset/" +output_path: "/cache/output/" +load_path: "/cache/load_checkpoint/" +device_target: "Ascend" + +log_save_path: "./log/PCB/market/train" +checkpoint_save_path: "./checkpoint/PCB/market/train" +checkpoint_file_path: "/cache/load_checkpoint/pretrained_resnet50.ckpt" +# ========================================================================= + +# dataset setting +mindrecord_dir: "./MindRecord" +dataset_name: "market" +batch_size: 64 +num_parallel_workers: 4 +device_num: 1 + +# model setting +model_name: "PCB" + +# optimizer setting +learning_rate: 0.1 +lr_mult: 0.1 +decay_rate: 0.1 +momentum: 0.9 +weight_decay: 5e-4 +nesterov: True +loss_scale: 1.0 + +# training setting +mode_name: "GRAPH" +sink_mode: True +seed: 37 +epoch_size: 60 +decay_epoch_size: 40 +warmup_epoch_size: 1 + +# checkpoint callbacks setting +save_checkpoint: True +save_checkpoint_epochs: 60 +keep_checkpoint_max: 15 + +# EvalCallBack setting +run_eval: False +eval_interval: 15 +eval_start_epoch: 60 + +use_G_feature: True diff --git a/research/cv/pcb/config/train_RPP_cuhk03/finetune_RPP.yaml b/research/cv/pcb/config/train_RPP_cuhk03/finetune_RPP.yaml new file mode 100644 index 0000000000000000000000000000000000000000..8bf5cb9ec2c37f16c98e0be46bead62e6b153c41 --- /dev/null +++ b/research/cv/pcb/config/train_RPP_cuhk03/finetune_RPP.yaml @@ -0,0 +1,57 @@ +# Builtin Configurations(DO NOT CHANGE THESE CONFIGURATIONS unless you know exactly what you are doing) + +enable_modelarts: False +# Url for modelarts +data_url: "" +train_url: "" +checkpoint_url: "" +# Path for local +run_distribute: False +enable_profiling: False +dataset_path: "/cache/dataset/" +output_path: "/cache/output/" +load_path: "/cache/load_checkpoint/" +device_target: "Ascend" +log_save_path: "./log/RPP/cuhk03/train" +checkpoint_save_path: "./checkpoint/RPP/cuhk03/train" +checkpoint_file_path: "/cache/load_checkpoint/RPP-45_115.ckpt" +# ========================================================================= + +# dataset setting +mindrecord_dir: "./MindRecord" +dataset_name: "cuhk03" +batch_size: 64 +num_parallel_workers: 4 +device_num: 1 + +# model setting +model_name: "RPP" + +# optimizer setting +learning_rate: 0.005 +lr_mult: 0.5 +decay_rate: 0.5 +momentum: 0.9 +weight_decay: 5e-4 +nesterov: True +loss_scale: 1.0 + +# training setting +mode_name: "GRAPH" +sink_mode: True +seed: 37 +epoch_size: 10 +decay_epoch_size: 10 +warmup_epoch_size: 0 + +# checkpoint callbacks setting +save_checkpoint: True +save_checkpoint_epochs: 10 +keep_checkpoint_max: 15 + +# EvalCallBack setting +run_eval: False +eval_interval: 15 +eval_start_epoch: 60 + +use_G_feature: True diff --git a/research/cv/pcb/config/train_RPP_cuhk03/train_PCB.yaml b/research/cv/pcb/config/train_RPP_cuhk03/train_PCB.yaml new file mode 100644 index 0000000000000000000000000000000000000000..71c926c11fc4eb5afa6dfa877018a5a109012a4d --- /dev/null +++ b/research/cv/pcb/config/train_RPP_cuhk03/train_PCB.yaml @@ -0,0 +1,57 @@ +# Builtin Configurations(DO NOT CHANGE THESE CONFIGURATIONS unless you know exactly what you are doing) + +enable_modelarts: False +# Url for modelarts +data_url: "" +train_url: "" +checkpoint_url: "" +# Path for local +run_distribute: False +enable_profiling: False +dataset_path: "/cache/dataset/" +output_path: "/cache/output/" +load_path: "/cache/load_checkpoint/" +device_target: "Ascend" +log_save_path: "./log/RPP/cuhk03/train" +checkpoint_save_path: "./checkpoint/RPP/cuhk03/train" +checkpoint_file_path: "/cache/load_checkpoint/pretrained_resnet50.ckpt" +# ========================================================================= + +# dataset setting +mindrecord_dir: "./MindRecord" +dataset_name: "cuhk03" +batch_size: 64 +num_parallel_workers: 4 +device_num: 1 + +# model setting +model_name: "PCB" + +# optimizer setting +learning_rate: 0.1 +lr_mult: 0.1 +decay_rate: 0.1 +momentum: 0.9 +weight_decay: 5e-4 +nesterov: True +loss_scale: 1.0 + +# training setting +mode_name: "GRAPH" +sink_mode: True +seed: 37 +epoch_size: 40 +decay_epoch_size: 40 +warmup_epoch_size: 1 + +# checkpoint callbacks setting +save_checkpoint: True +save_checkpoint_epochs: 40 +keep_checkpoint_max: 15 + +# EvalCallBack setting +run_eval: False +eval_interval: 15 +eval_start_epoch: 60 + +use_G_feature: True diff --git a/research/cv/pcb/config/train_RPP_cuhk03/train_RPP.yaml b/research/cv/pcb/config/train_RPP_cuhk03/train_RPP.yaml new file mode 100644 index 0000000000000000000000000000000000000000..4b6b5e772297458f9c4c8c2e0db05b228c2836a1 --- /dev/null +++ b/research/cv/pcb/config/train_RPP_cuhk03/train_RPP.yaml @@ -0,0 +1,57 @@ +# Builtin Configurations(DO NOT CHANGE THESE CONFIGURATIONS unless you know exactly what you are doing) + +enable_modelarts: False +# Url for modelarts +data_url: "" +train_url: "" +checkpoint_url: "" +# Path for local +run_distribute: False +enable_profiling: False +dataset_path: "/cache/dataset/" +output_path: "/cache/output/" +load_path: "/cache/load_checkpoint/" +device_target: "Ascend" +log_save_path: "./log/RPP/cuhk03/train" +checkpoint_save_path: "./checkpoint/RPP/cuhk03/train" +checkpoint_file_path: "/cache/load_checkpoint/PCB-40_115.ckpt" +# ========================================================================= + +# dataset setting +mindrecord_dir: "./MindRecord" +dataset_name: "cuhk03" +batch_size: 64 +num_parallel_workers: 4 +device_num: 1 + +# model setting +model_name: "RPP" + +# optimizer setting +learning_rate: 0.05 +lr_mult: 0.5 +decay_rate: 0.5 +momentum: 0.9 +weight_decay: 5e-4 +nesterov: True +loss_scale: 1.0 + +# training setting +mode_name: "GRAPH" +sink_mode: True +seed: 37 +epoch_size: 45 +decay_epoch_size: 15 +warmup_epoch_size: 0 + +# checkpoint callbacks setting +save_checkpoint: True +save_checkpoint_epochs: 45 +keep_checkpoint_max: 15 + +# EvalCallBack setting +run_eval: False +eval_interval: 15 +eval_start_epoch: 60 + +use_G_feature: True diff --git a/research/cv/pcb/config/train_RPP_duke/train_PCB.yaml b/research/cv/pcb/config/train_RPP_duke/train_PCB.yaml new file mode 100644 index 0000000000000000000000000000000000000000..e5696f50e2e1ce9bed475c9e97ad7c6af8425613 --- /dev/null +++ b/research/cv/pcb/config/train_RPP_duke/train_PCB.yaml @@ -0,0 +1,57 @@ +# Builtin Configurations(DO NOT CHANGE THESE CONFIGURATIONS unless you know exactly what you are doing) + +enable_modelarts: False +# Url for modelarts +data_url: "" +train_url: "" +checkpoint_url: "" +# Path for local +run_distribute: False +enable_profiling: False +dataset_path: "/cache/dataset/" +output_path: "/cache/output/" +load_path: "/cache/load_checkpoint/" +device_target: "Ascend" +log_save_path: "./log/RPP/duke/train" +checkpoint_save_path: "./checkpoint/RPP/duke/train" +checkpoint_file_path: "/cache/load_checkpoint/pretrained_resnet50.ckpt" +# ========================================================================= + +# dataset setting +mindrecord_dir: "./MindRecord" +dataset_name: "duke" +batch_size: 64 +num_parallel_workers: 4 +device_num: 1 + +# model setting +model_name: "PCB" + +# optimizer setting +learning_rate: 0.1 +lr_mult: 0.1 +decay_rate: 0.1 +momentum: 0.9 +weight_decay: 5e-4 +nesterov: True +loss_scale: 1.0 + +# training setting +mode_name: "GRAPH" +sink_mode: True +seed: 1 +epoch_size: 20 +decay_epoch_size: 20 +warmup_epoch_size: 0 + +# checkpoint callbacks setting +save_checkpoint: True +save_checkpoint_epochs: 20 +keep_checkpoint_max: 15 + +# EvalCallBack setting +run_eval: False +eval_interval: 15 +eval_start_epoch: 60 + +use_G_feature: True diff --git a/research/cv/pcb/config/train_RPP_duke/train_RPP.yaml b/research/cv/pcb/config/train_RPP_duke/train_RPP.yaml new file mode 100644 index 0000000000000000000000000000000000000000..c957b224cef77abba47d793f182176edf131c89c --- /dev/null +++ b/research/cv/pcb/config/train_RPP_duke/train_RPP.yaml @@ -0,0 +1,57 @@ +# Builtin Configurations(DO NOT CHANGE THESE CONFIGURATIONS unless you know exactly what you are doing) + +enable_modelarts: False +# Url for modelarts +data_url: "" +train_url: "" +checkpoint_url: "" +# Path for local +run_distribute: False +enable_profiling: False +dataset_path: "/cache/dataset/" +output_path: "/cache/output/" +load_path: "/cache/load_checkpoint/" +device_target: "Ascend" +log_save_path: "./log/RPP/duke/train" +checkpoint_save_path: "./checkpoint/RPP/duke/train" +checkpoint_file_path: "/cache/load_checkpoint/PCB-20_258.ckpt" +# ========================================================================= + +# dataset setting +mindrecord_dir: "./MindRecord" +dataset_name: "duke" +batch_size: 64 +num_parallel_workers: 4 +device_num: 1 + +# model setting +model_name: "RPP" + +# optimizer setting +learning_rate: 0.01 +lr_mult: 1.0 +decay_rate: 0.1 +momentum: 0.9 +weight_decay: 5e-4 +nesterov: True +loss_scale: 1.0 + +# training setting +mode_name: "GRAPH" +sink_mode: True +seed: 1 +epoch_size: 40 +decay_epoch_size: 20 +warmup_epoch_size: 0 + +# checkpoint callbacks setting +save_checkpoint: True +save_checkpoint_epochs: 40 +keep_checkpoint_max: 15 + +# EvalCallBack setting +run_eval: False +eval_interval: 15 +eval_start_epoch: 60 + +use_G_feature: True diff --git a/research/cv/pcb/config/train_RPP_market/finetune_RPP.yaml b/research/cv/pcb/config/train_RPP_market/finetune_RPP.yaml new file mode 100644 index 0000000000000000000000000000000000000000..fcdce9ad940372098c74f419cc0dc790c3488388 --- /dev/null +++ b/research/cv/pcb/config/train_RPP_market/finetune_RPP.yaml @@ -0,0 +1,57 @@ +# Builtin Configurations(DO NOT CHANGE THESE CONFIGURATIONS unless you know exactly what you are doing) + +enable_modelarts: False +# Url for modelarts +data_url: "" +train_url: "" +checkpoint_url: "" +# Path for local +run_distribute: False +enable_profiling: False +dataset_path: "/cache/dataset/" +output_path: "/cache/output/" +load_path: "/cache/load_checkpoint/" +device_target: "Ascend" +log_save_path: "./log/RPP/market/train" +checkpoint_save_path: "./checkpoint/RPP/market/train" +checkpoint_file_path: "/cache/load_checkpoint/RPP-45_202.ckpt" +# ========================================================================= + +# dataset setting +mindrecord_dir: "./MindRecord" +dataset_name: "market" +batch_size: 64 +num_parallel_workers: 4 +device_num: 1 + +# model setting +model_name: "RPP" + +# optimizer setting +learning_rate: 0.001 +lr_mult: 1.2 +decay_rate: 0.5 +momentum: 0.9 +weight_decay: 5e-4 +nesterov: True +loss_scale: 1.0 + +# training setting +mode_name: "GRAPH" +sink_mode: True +seed: 37 +epoch_size: 10 +decay_epoch_size: 10 +warmup_epoch_size: 0 + +# checkpoint callbacks setting +save_checkpoint: True +save_checkpoint_epochs: 10 +keep_checkpoint_max: 15 + +# EvalCallBack setting +run_eval: False +eval_interval: 15 +eval_start_epoch: 60 + +use_G_feature: True diff --git a/research/cv/pcb/config/train_RPP_market/train_PCB.yaml b/research/cv/pcb/config/train_RPP_market/train_PCB.yaml new file mode 100644 index 0000000000000000000000000000000000000000..0fd571f2e1b7845f1ef2b3ea458d0a6a3af8fc83 --- /dev/null +++ b/research/cv/pcb/config/train_RPP_market/train_PCB.yaml @@ -0,0 +1,57 @@ +# Builtin Configurations(DO NOT CHANGE THESE CONFIGURATIONS unless you know exactly what you are doing) + +enable_modelarts: False +# Url for modelarts +data_url: "" +train_url: "" +checkpoint_url: "" +# Path for local +run_distribute: False +enable_profiling: False +dataset_path: "/cache/dataset/" +output_path: "/cache/output/" +load_path: "/cache/load_checkpoint/" +device_target: "Ascend" +log_save_path: "./log/RPP/market/train" +checkpoint_save_path: "./checkpoint/RPP/market/train" +checkpoint_file_path: "/cache/load_checkpoint/pretrained_resnet50.ckpt" +# ========================================================================= + +# dataset setting +mindrecord_dir: "./MindRecord" +dataset_name: "market" +batch_size: 64 +num_parallel_workers: 4 +device_num: 1 + +# model setting +model_name: "PCB" + +# optimizer setting +learning_rate: 0.1 +lr_mult: 0.1 +decay_rate: 0.1 +momentum: 0.9 +weight_decay: 5e-4 +nesterov: True +loss_scale: 1.0 + +# training setting +mode_name: "GRAPH" +sink_mode: True +seed: 37 +epoch_size: 20 +decay_epoch_size: 20 +warmup_epoch_size: 1 + +# checkpoint callbacks setting +save_checkpoint: True +save_checkpoint_epochs: 20 +keep_checkpoint_max: 15 + +# EvalCallBack setting +run_eval: False +eval_interval: 15 +eval_start_epoch: 60 + +use_G_feature: True diff --git a/research/cv/pcb/config/train_RPP_market/train_RPP.yaml b/research/cv/pcb/config/train_RPP_market/train_RPP.yaml new file mode 100644 index 0000000000000000000000000000000000000000..1cb1567821b216266e7cfe926304a64c114d6165 --- /dev/null +++ b/research/cv/pcb/config/train_RPP_market/train_RPP.yaml @@ -0,0 +1,57 @@ +# Builtin Configurations(DO NOT CHANGE THESE CONFIGURATIONS unless you know exactly what you are doing) + +enable_modelarts: False +# Url for modelarts +data_url: "" +train_url: "" +checkpoint_url: "" +# Path for local +run_distribute: False +enable_profiling: False +dataset_path: "/cache/dataset/" +output_path: "/cache/output/" +load_path: "/cache/load_checkpoint/" +device_target: "Ascend" +log_save_path: "./log/RPP/market/train" +checkpoint_save_path: "./checkpoint/RPP/market/train" +checkpoint_file_path: "/cache/load_checkpoint/PCB-20_202.ckpt" +# ========================================================================= + +# dataset setting +mindrecord_dir: "./MindRecord" +dataset_name: "market" +batch_size: 64 +num_parallel_workers: 4 +device_num: 1 + +# model setting +model_name: "RPP" + +# optimizer setting +learning_rate: 0.01 +lr_mult: 1.2 +decay_rate: 0.5 +momentum: 0.9 +weight_decay: 5e-4 +nesterov: True +loss_scale: 1.0 + +# training setting +mode_name: "GRAPH" +sink_mode: True +seed: 37 +epoch_size: 45 +decay_epoch_size: 15 +warmup_epoch_size: 0 + +# checkpoint callbacks setting +save_checkpoint: True +save_checkpoint_epochs: 45 +keep_checkpoint_max: 15 + +# EvalCallBack setting +run_eval: False +eval_interval: 15 +eval_start_epoch: 60 + +use_G_feature: True diff --git a/research/cv/pcb/eval.py b/research/cv/pcb/eval.py new file mode 100644 index 0000000000000000000000000000000000000000..6ac293c999759d53dfc937d0011ad38de8818793 --- /dev/null +++ b/research/cv/pcb/eval.py @@ -0,0 +1,84 @@ +# 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. +# ============================================================================ +"""eval.py""" + +import os +import sys +from mindspore import context +from mindspore import load_checkpoint, load_param_into_net + +from src.model_utils.config import config +from src.dataset import create_dataset +from src.pcb import PCB +from src.rpp import RPP +from src.eval_utils import apply_eval +from src.logging import Logger +from src.model_utils.moxing_adapter import moxing_wrapper + +def build_model(num_classes): + model = None + if config.model_name == "PCB": + model = PCB(num_classes) + elif config.model_name == "RPP": + model = RPP(num_classes) + return model + +@moxing_wrapper() +def eval_net(): + """eval_net""" + target = config.device_target + #init context + context.set_context(mode=context.GRAPH_MODE, device_target="Ascend", save_graphs=False) + if target == "Ascend": + device_id = int(os.getenv('DEVICE_ID', '0')) + context.set_context(device_id=device_id) + log_save_dir = os.path.join(config.output_path, config.log_save_path) + if not os.path.isdir(log_save_dir): + os.makedirs(log_save_dir) + # Redirect print to both console and log file + sys.stdout = Logger(os.path.join(log_save_dir, 'log.txt')) + #create_dataset + _, train_set = \ +create_dataset(dataset_name=config.dataset_name, dataset_path=config.dataset_path, \ +subset_name="train", batch_size=config.batch_size, num_parallel_workers=config.num_parallel_workers) + print("Loading query dataset...") + query_dataset, query_set = \ +create_dataset(dataset_name=config.dataset_name, dataset_path=config.dataset_path, \ +subset_name="query", batch_size=config.batch_size, num_parallel_workers=config.num_parallel_workers) + print("Loading gallery dataset...") + gallery_dataset, gallery_set = \ +create_dataset(dataset_name=config.dataset_name, dataset_path=config.dataset_path, \ +subset_name="gallery", batch_size=config.batch_size, num_parallel_workers=config.num_parallel_workers) + #network + num_classes = train_set.num_ids + eval_network = build_model(num_classes) + print("Load Checkpoint!") + #load checkpoint + if config.checkpoint_file_path != "": + param_dict = load_checkpoint(config.checkpoint_file_path) + load_param_into_net(eval_network, param_dict) + #apply eval + print("Processing, please wait a moment.") + eval_param_dict = {"net": eval_network, "query_dataset": query_dataset, "gallery_dataset": gallery_dataset, \ +"query_set": query_set.data, "gallery_set": gallery_set.data} + mAP, cmc_scores = apply_eval(eval_param_dict) + print('Mean AP: {:4.1%}'.format(mAP), flush=True) + print('CMC Scores{:>12}'.format(config.dataset_name), flush=True) + cmc_topk = (1, 5, 10) + for k in cmc_topk: + print(' top-{:<4}{:12.1%}'.format(k, cmc_scores[config.dataset_name][k - 1]), flush=True) + +if __name__ == "__main__": + eval_net() diff --git a/research/cv/pcb/export.py b/research/cv/pcb/export.py new file mode 100644 index 0000000000000000000000000000000000000000..987e3fa312e2a0a463cce9561db3f7bdd7415868 --- /dev/null +++ b/research/cv/pcb/export.py @@ -0,0 +1,60 @@ +# 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. +# ============================================================================ + + +"""export checkpoint file into mindir models""" + +import os +import numpy as np +import mindspore as ms +from mindspore import Tensor, context, load_checkpoint, load_param_into_net, export + +from src.pcb import PCB_infer +from src.rpp import RPP_infer + +from src.model_utils.config import config +from src.model_utils.device_adapter import get_device_id +from src.model_utils.moxing_adapter import moxing_wrapper + +def build_model(): + model = None + if config.model_name == "PCB": + model = PCB_infer() + elif config.model_name == "RPP": + model = RPP_infer() + return model + +def modelarts_pre_process(): + '''modelarts pre process function.''' + config.file_name = os.path.join(config.output_path, config.file_name) + +@moxing_wrapper(pre_process=modelarts_pre_process) +def run_export(): + """run export.""" + context.set_context(mode=context.GRAPH_MODE, device_target=config.device_target) + if config.device_target == "Ascend": + context.set_context(device_id=get_device_id()) + # define network + network = build_model() + assert config.checkpoint_file_path is not None, "checkpoint_path is None." + # load network checkpoint + param_dict = load_checkpoint(config.checkpoint_file_path) + load_param_into_net(network, param_dict) + # export network + inputs = Tensor(np.zeros([config.batch_size, 3, config.image_height, config.image_width]), ms.float32) + export(network, inputs, file_name=config.file_name, file_format=config.file_format) + +if __name__ == '__main__': + run_export() diff --git a/research/cv/pcb/pip-requirements.txt b/research/cv/pcb/pip-requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..01aed221916f97475962e2626a174445f2ce8b1f --- /dev/null +++ b/research/cv/pcb/pip-requirements.txt @@ -0,0 +1,4 @@ +sympy==1.4 +imageio==2.16.0 +h5py==2.10.0 +PyYAML==5.3.1 diff --git a/research/cv/pcb/postprocess.py b/research/cv/pcb/postprocess.py new file mode 100644 index 0000000000000000000000000000000000000000..2dfac2394e61913fb553a9367073f3664313f04a --- /dev/null +++ b/research/cv/pcb/postprocess.py @@ -0,0 +1,90 @@ +# 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. +# ============================================================================ + + +"""post process for 310 inference""" +import os +import numpy as np +from src.model_utils.config import config +from src.eval_utils import evaluate + +def apply_eval(query_feature, gallery_feature, query_label, gallery_label, query_cam, gallery_cam): + """Compute CMC and mAP""" + CMC = np.zeros((len(gallery_label),)) + ap = 0.0 + for i in range(len(query_label)): + ap_tmp, CMC_tmp = evaluate(query_feature[i], query_label[i], query_cam[i], \ +gallery_feature, gallery_label, gallery_cam) + if CMC_tmp[0] == -1: + continue + CMC = CMC + CMC_tmp + ap += ap_tmp + CMC = CMC / len(query_label) + mAP = ap / len(query_label) + return mAP, CMC + +def postprocess(): + """Postprocess""" + feature_dim = 256 + if config.use_G_feature: + feature_dim = 2048 + query_pid_path = os.path.join(config.preprocess_result_path, "query", "pid") + query_camid_path = os.path.join(config.preprocess_result_path, "query", "camid") + query_prediction_path = config.query_prediction_path + query_file_names = os.listdir(query_pid_path) + query_pids = [] + query_camids = [] + query_predictions = [] + for f in query_file_names: + pid = np.fromfile(os.path.join(query_pid_path, f), dtype=np.int32).tolist() + camid = np.fromfile(os.path.join(query_camid_path, f), dtype=np.int32).tolist() + prediction = np.fromfile(os.path.join(query_prediction_path, f), \ + dtype=np.float32).reshape((1, feature_dim, 6, 1)) + query_pids += pid + query_camids += camid + query_predictions.append(prediction) + query_pids = np.asarray(query_pids) + query_camids = np.asarray(query_camids) + query_predictions = np.concatenate(query_predictions, axis=0) + query_predictions = query_predictions.reshape(query_predictions.shape[0], -1) + gallery_pid_path = os.path.join(config.preprocess_result_path, "gallery", "pid") + gallery_camid_path = os.path.join(config.preprocess_result_path, "gallery", "camid") + gallery_prediction_path = config.gallery_prediction_path + gallery_file_names = os.listdir(gallery_pid_path) + gallery_pids = [] + gallery_camids = [] + gallery_predictions = [] + for f in gallery_file_names: + pid = np.fromfile(os.path.join(gallery_pid_path, f), dtype=np.int32).tolist() + camid = np.fromfile(os.path.join(gallery_camid_path, f), dtype=np.int32).tolist() + prediction = np.fromfile(os.path.join(gallery_prediction_path, f), \ + dtype=np.float32).reshape((1, feature_dim, 6, 1)) + gallery_pids += pid + gallery_camids += camid + gallery_predictions.append(prediction) + gallery_pids = np.asarray(gallery_pids) + gallery_camids = np.asarray(gallery_camids) + gallery_predictions = np.concatenate(gallery_predictions, axis=0) + gallery_predictions = gallery_predictions.reshape(gallery_predictions.shape[0], -1) + mAP_score, CMC_score = apply_eval(query_predictions, gallery_predictions, query_pids, \ + gallery_pids, query_camids, gallery_camids) + # print metrics + print('Mean AP: {:4.1%}'.format(mAP_score), flush=True) + cmc_topk = (1, 5, 10) + for k in cmc_topk: + print(' top-{:<4}{:12.1%}'.format(k, CMC_score[k - 1]), flush=True) + +if __name__ == "__main__": + postprocess() diff --git a/research/cv/pcb/preprocess.py b/research/cv/pcb/preprocess.py new file mode 100644 index 0000000000000000000000000000000000000000..6b825b6cbf4f97431ed464724888bc9c4e95f3ff --- /dev/null +++ b/research/cv/pcb/preprocess.py @@ -0,0 +1,78 @@ +# 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. +# ============================================================================ + + +"""pre process for 310 inference""" +import os +from src.dataset import create_dataset +from src.model_utils.config import config + +def preprocess(): + """Preprocess""" + print("Loading query dataset...") + query_dataset, _ = create_dataset(dataset_name=config.dataset_name, dataset_path=config.dataset_path, \ + subset_name="query", batch_size=config.batch_size, \ + num_parallel_workers=config.num_parallel_workers) + print("Loading gallery dataset...") + gallery_dataset, _ = create_dataset(dataset_name=config.dataset_name, dataset_path=config.dataset_path, \ + subset_name="gallery", batch_size=config.batch_size, \ + num_parallel_workers=config.num_parallel_workers) + query_img_path = os.path.join(config.preprocess_result_path, "query", "image") + query_fid_path = os.path.join(config.preprocess_result_path, "query", "fid") + query_pid_path = os.path.join(config.preprocess_result_path, "query", "pid") + query_camid_path = os.path.join(config.preprocess_result_path, "query", "camid") + gallery_img_path = os.path.join(config.preprocess_result_path, "gallery", "image") + gallery_fid_path = os.path.join(config.preprocess_result_path, "gallery", "fid") + gallery_pid_path = os.path.join(config.preprocess_result_path, "gallery", "pid") + gallery_camid_path = os.path.join(config.preprocess_result_path, "gallery", "camid") + paths = [query_img_path, query_fid_path, query_pid_path, query_camid_path, \ + gallery_img_path, gallery_fid_path, gallery_pid_path, gallery_camid_path] + for path in paths: + if not os.path.isdir(path): + os.makedirs(path) + print("Processing query dataset...") + for idx, data in enumerate(query_dataset.create_dict_iterator(output_numpy=True)): + img = data["image"] + fid = data["fid"] + pid = data["pid"] + camid = data["camid"] + file_name = config.dataset_name + "_" + str(idx) + ".bin" + img_file_path = os.path.join(query_img_path, file_name) + fid_file_path = os.path.join(query_fid_path, file_name) + pid_file_path = os.path.join(query_pid_path, file_name) + camid_file_path = os.path.join(query_camid_path, file_name) + img.tofile(img_file_path) + fid.tofile(fid_file_path) + pid.tofile(pid_file_path) + camid.tofile(camid_file_path) + print("Processing gallery dataset...") + for idx, data in enumerate(gallery_dataset.create_dict_iterator(output_numpy=True)): + img = data["image"] + fid = data["fid"] + pid = data["pid"] + camid = data["camid"] + file_name = config.dataset_name + "_" + str(idx) + ".bin" + img_file_path = os.path.join(gallery_img_path, file_name) + fid_file_path = os.path.join(gallery_fid_path, file_name) + pid_file_path = os.path.join(gallery_pid_path, file_name) + camid_file_path = os.path.join(gallery_camid_path, file_name) + img.tofile(img_file_path) + fid.tofile(fid_file_path) + pid.tofile(pid_file_path) + camid.tofile(camid_file_path) + print("=" * 20, "export bin files finished", "=" * 20) + +if __name__ == "__main__": + preprocess() diff --git a/research/cv/pcb/scripts/run_distribute_train.sh b/research/cv/pcb/scripts/run_distribute_train.sh new file mode 100644 index 0000000000000000000000000000000000000000..3ac43bffccf6a372ac1aa638ad4929961ea3a0f4 --- /dev/null +++ b/research/cv/pcb/scripts/run_distribute_train.sh @@ -0,0 +1,154 @@ +#!/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. +# ============================================================================ + +if [ $# != 5 ] && [ $# != 6 ] +then + echo "Usage: bash run_distribute_train.sh [RANK_TABLE_FILE] [MODEL_NAME] [DATASET_NAME] [DATASET_PATH] [CONFIG_PATH] [PRETRAINED_CKPT_PATH](optional)" + exit 1 +fi + + +get_real_path(){ + if [ "${1:0:1}" == "/" ]; then + echo "$1" + else + echo "$(realpath -m $PWD/$1)" + fi +} + +RANK_TABLE_FILE=$(get_real_path $1) +MODEL_NAME=$2 +DATASET_NAME=$3 +DATASET_PATH=$(get_real_path $4) +CONFIG_PATH=$(get_real_path $5) + +if [ $# == 6 ]; then + PRETRAINED_CKPT_PATH=$(get_real_path $6) +else + PRETRAINED_CKPT_PATH="" +fi + +if [ ! -f $RANK_TABLE_FILE ] +then + echo "error: RANK_TABLE_FILE=$RANK_TABLE_FILE is not a file" +exit 1 +fi + +if [ $MODEL_NAME != "PCB" ] && [ $MODEL_NAME != "RPP" ] +then + echo "error: MODEL_NAME=$MODEL_NAME is invalid, please choose from ['PCB','RPP']" +exit 1 +fi + +if [ $DATASET_NAME != "market" ] && [ $DATASET_NAME != "duke" ] && [ $DATASET_NAME != "cuhk03" ] +then + echo "error: DATASET_NAME=$DATASET_NAME is invalid, please choose from ['market','duke','cuhk03']" +exit 1 +fi + +if [ ! -d $DATASET_PATH ] +then + echo "error: DATASET_PATH=$DATASET_PATH is not a directory" +exit 1 +fi + +if ( [ $MODEL_NAME = "PCB" ] && [ $DATASET_NAME = "market" ] ) || ( [ $MODEL_NAME = "PCB" ] && [ $DATASET_NAME = "duke" ] ) +then + if [ ! -f $CONFIG_PATH ] + then + echo "error: CONFIG_PATH=$CONFIG_PATH is not a file" + exit 1 + fi +else + if [ ! -d $CONFIG_PATH ] + then + echo "error: CONFIG_PATH=$CONFIG_PATH is not a directory" + exit 1 + fi +fi + +if [ $# == 6 ] && [ ! -f $PRETRAINED_CKPT_PATH ] +then + echo "error: PRETRAINED_CKPT_PATH=$PRETRAINED_CKPT_PATH is not a file" +exit 1 +fi + +ulimit -u unlimited +export DEVICE_NUM=8 +export RANK_SIZE=8 +export RANK_TABLE_FILE=$RANK_TABLE_FILE + +export SERVER_ID=0 +rank_start=$((DEVICE_NUM * SERVER_ID)) + +cpus=`cat /proc/cpuinfo| grep "processor"| wc -l` +avg=`expr $cpus \/ $DEVICE_NUM` +gap=`expr $avg \- 1` + +script_path=$(readlink -f "$0") +script_dir_path=$(dirname "${script_path}") + +LOG_SAVE_PATH=${script_dir_path}/output/log/${MODEL_NAME}/${DATASET_NAME}/train/ +CHECKPOINT_SAVE_PATH=${script_dir_path}/output/checkpoint/${MODEL_NAME}/${DATASET_NAME}/train/ + +if [ -d ${LOG_SAVE_PATH} ]; +then + rm -rf ${LOG_SAVE_PATH} +fi + +if [ -d ${CHECKPOINT_SAVE_PATH} ]; +then + rm -rf ${CHECKPOINT_SAVE_PATH} +fi + +distribute_train(){ + for((i=0; i<${DEVICE_NUM}; i++)) + do + start=`expr $i \* $avg` + end=`expr $start \+ $gap` + cmdopt=$start"-"$end + export DEVICE_ID=${i} + export RANK_ID=$((rank_start + i)) + echo "start training for rank $RANK_ID, device $DEVICE_ID" + taskset -c $cmdopt python ${script_dir_path}/../train.py --run_distribute=True --device_num=$RANK_SIZE --dataset_path=$DATASET_PATH --config_path=$1 --checkpoint_file_path=$2 --output_path=${script_dir_path}/output/ & + done +} + +if [ $MODEL_NAME = "PCB" ] && [ $DATASET_NAME = "market" ]; then + distribute_train $CONFIG_PATH $PRETRAINED_CKPT_PATH +elif [ $MODEL_NAME = "PCB" ] && [ $DATASET_NAME = "duke" ]; then + distribute_train $CONFIG_PATH $PRETRAINED_CKPT_PATH +elif [ $MODEL_NAME = "PCB" ] && [ $DATASET_NAME = "cuhk03" ]; then + distribute_train $CONFIG_PATH/train_PCB.yaml $PRETRAINED_CKPT_PATH + wait + distribute_train $CONFIG_PATH/finetune_PCB.yaml ${CHECKPOINT_SAVE_PATH}/ckpt_0/PCB-40_14.ckpt +elif [ $MODEL_NAME = "RPP" ] && [ $DATASET_NAME = "market" ]; then + distribute_train ${CONFIG_PATH}/train_PCB.yaml $PRETRAINED_CKPT_PATH + wait + distribute_train ${CONFIG_PATH}/train_RPP.yaml ${CHECKPOINT_SAVE_PATH}/ckpt_0/PCB-20_25.ckpt + wait + distribute_train ${CONFIG_PATH}/finetune_RPP.yaml ${CHECKPOINT_SAVE_PATH}/ckpt_0/RPP-45_25.ckpt +elif [ $MODEL_NAME = "RPP" ] && [ $DATASET_NAME = "duke" ]; then + distribute_train ${CONFIG_PATH}/train_PCB.yaml $PRETRAINED_CKPT_PATH + wait + distribute_train ${CONFIG_PATH}/train_RPP.yaml ${CHECKPOINT_SAVE_PATH}/ckpt_0/PCB-20_32.ckpt +else + distribute_train ${CONFIG_PATH}/train_PCB.yaml $PRETRAINED_CKPT_PATH + wait + distribute_train ${CONFIG_PATH}/train_RPP.yaml ${CHECKPOINT_SAVE_PATH}/ckpt_0/PCB-40_14.ckpt + wait + distribute_train ${CONFIG_PATH}/finetune_RPP.yaml ${CHECKPOINT_SAVE_PATH}/ckpt_0/RPP-45_14.ckpt +fi diff --git a/research/cv/pcb/scripts/run_eval.sh b/research/cv/pcb/scripts/run_eval.sh new file mode 100644 index 0000000000000000000000000000000000000000..2a6bcbe4366d0919543350f96d3b1cbb2ab9eab6 --- /dev/null +++ b/research/cv/pcb/scripts/run_eval.sh @@ -0,0 +1,80 @@ +#!/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. +# ============================================================================ + + +if [ $# != 6 ] +then + echo "Usage: bash run_eval.sh [MODEL_NAME] [DATASET_NAME] [DATASET_PATH] [CONFIG_PATH] [CHECKPOINT_PATH] [USE_G_FEATURE]" +exit 1 +fi + +get_real_path(){ + if [ "${1:0:1}" == "/" ]; then + echo "$1" + else + echo "$(realpath -m $PWD/$1)" + fi +} + +MODEL_NAME=$1 +DATASET_NAME=$2 +DATASET_PATH=$(get_real_path $3) +CONFIG_PATH=$(get_real_path $4) +CHECKPOINT_PATH=$(get_real_path $5) +USE_G_FEATURE=$6 + +if [ $MODEL_NAME != "PCB" ] && [ $MODEL_NAME != "RPP" ] +then + echo "error: MODEL_NAME=$MODEL_NAME is invalid, please choose from ['PCB','RPP']" +exit 1 +fi + +if [ $DATASET_NAME != "market" ] && [ $DATASET_NAME != "duke" ] && [ $DATASET_NAME != "cuhk03" ] +then + echo "error: DATASET_NAME=$DATASET_NAME is invalid, please choose from ['market','duke','cuhk03']" +exit 1 +fi + +if [ ! -d $DATASET_PATH ] +then + echo "error: DATASET_PATH=$DATASET_PATH is not a directory" +exit 1 +fi + +if [ ! -f $CONFIG_PATH ] +then + echo "error: CONFIG_PATH=$CONFIG_PATH is not a file" +exit 1 +fi + +if [ ! -f $CHECKPOINT_PATH ] +then + echo "error: CHECKPOINT_PATH=$CHECKPOINT_PATH is not a file" +exit 1 +fi + + +script_path=$(readlink -f "$0") +script_dir_path=$(dirname "${script_path}") + +LOG_SAVE_PATH=${script_dir_path}/output/log/${MODEL_NAME}/${DATASET_NAME}/eval/ + +if [ -d ${LOG_SAVE_PATH} ]; +then + rm -rf ${LOG_SAVE_PATH} +fi + +python ${script_dir_path}/../eval.py --dataset_path=$DATASET_PATH --config_path=$CONFIG_PATH --checkpoint_file_path=$CHECKPOINT_PATH --use_G_feature=$USE_G_FEATURE --output_path ${script_dir_path}/output/ diff --git a/research/cv/pcb/scripts/run_infer_310.sh b/research/cv/pcb/scripts/run_infer_310.sh new file mode 100644 index 0000000000000000000000000000000000000000..65885ab1331e36efe5e5345d8b554a4c64010be4 --- /dev/null +++ b/research/cv/pcb/scripts/run_infer_310.sh @@ -0,0 +1,131 @@ +#!/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. +# ============================================================================ + + +if [[ $# -lt 5 || $# -gt 6 ]]; then + echo "Usage: bash run_infer_310.sh [MINDIR_PATH] [DATASET_NAME] [DATASET_PATH] [USE_G_FEATURE][CONFIG_PATH] [DEVICE_ID](optional) + DEVICE_ID is optional, it can be set by environment variable device_id, otherwise the value is zero" +exit 1 +fi + +get_real_path(){ + if [ "${1:0:1}" == "/" ]; then + echo "$1" + else + echo "$(realpath -m $PWD/$1)" + fi +} + +model=$(get_real_path $1) +dataset_name=$2 +dataset_path=$(get_real_path $3) +use_G_feature=$4 +config_path=$(get_real_path $5) +query_image_path=./preprocess_Result/query/image +gallery_image_path=./preprocess_Result/gallery/image + +device_id=0 +if [ $# == 6 ]; then + device_id=$6 +fi + +echo "mindir name: "$model +echo "dataset name: "$dataset_name +echo "dataset path: "$dataset_path +echo "use_G_feature: "$use_G_feature +echo "config path: "$config_path +echo "device id: "$device_id + +export ASCEND_HOME=/usr/local/Ascend/ +if [ -d ${ASCEND_HOME}/ascend-toolkit ]; then + export PATH=$ASCEND_HOME/fwkacllib/bin:$ASCEND_HOME/fwkacllib/ccec_compiler/bin:$ASCEND_HOME/ascend-toolkit/latest/fwkacllib/ccec_compiler/bin:$ASCEND_HOME/ascend-toolkit/latest/atc/bin:$PATH + export LD_LIBRARY_PATH=$ASCEND_HOME/fwkacllib/lib64:/usr/local/lib:$ASCEND_HOME/ascend-toolkit/latest/atc/lib64:$ASCEND_HOME/ascend-toolkit/latest/fwkacllib/lib64:$ASCEND_HOME/driver/lib64:$ASCEND_HOME/add-ons:$LD_LIBRARY_PATH + export TBE_IMPL_PATH=$ASCEND_HOME/ascend-toolkit/latest/opp/op_impl/built-in/ai_core/tbe + export PYTHONPATH=$ASCEND_HOME/fwkacllib/python/site-packages:${TBE_IMPL_PATH}:$ASCEND_HOME/ascend-toolkit/latest/fwkacllib/python/site-packages:$PYTHONPATH + export ASCEND_OPP_PATH=$ASCEND_HOME/ascend-toolkit/latest/opp +else + export ASCEND_HOME=/usr/local/Ascend/latest/ + export PATH=$ASCEND_HOME/fwkacllib/bin:$ASCEND_HOME/fwkacllib/ccec_compiler/bin:$ASCEND_HOME/atc/ccec_compiler/bin:$ASCEND_HOME/atc/bin:$PATH + export LD_LIBRARY_PATH=$ASCEND_HOME/fwkacllib/lib64:/usr/local/lib:$ASCEND_HOME/atc/lib64:$ASCEND_HOME/acllib/lib64:$ASCEND_HOME/driver/lib64:$ASCEND_HOME/add-ons:$LD_LIBRARY_PATH + export PYTHONPATH=$ASCEND_HOME/fwkacllib/python/site-packages:$ASCEND_HOME/atc/python/site-packages:$PYTHONPATH + export ASCEND_OPP_PATH=$ASCEND_HOME/opp +fi + + +function preprocess_data() +{ + if [ -d preprocess_Result ]; then + rm -rf ./preprocess_Result + fi + mkdir preprocess_Result + python ../preprocess.py --dataset_name=$dataset_name --dataset_path=$dataset_path --config_path=$config_path --preprocess_result_path=./preprocess_Result &> preprocess.log +} + + +function compile_app() +{ + cd ../ascend310_infer || exit + if [ -d out ]; then + rm -rf ./out + fi + bash build.sh &> build.log + cd - || exit +} + +function infer() +{ + if [ -d query_result_files ]; then + rm -rf ./query_result_files + fi + if [ -d gallery_result_files ]; then + rm -rf ./gallery_result_files + fi + if [ -d time_Result ]; then + rm -rf ./time_Result + fi + mkdir query_result_files + mkdir gallery_result_files + mkdir time_Result + ../ascend310_infer/out/main --mindir_path=$model --query_image_path=$query_image_path --gallery_image_path=$gallery_image_path --device_id=$device_id &> infer.log +} + + +function cal_metrics() +{ + python ../postprocess.py --preprocess_result_path=./preprocess_Result --query_prediction_path=./query_result_files --gallery_prediction_path=./gallery_result_files --use_G_feature=$use_G_feature --config_path=$config_path &> metrics.log +} + + +preprocess_data +if [ $? -ne 0 ]; then + echo "preprocess data failed" + exit 1 +fi +compile_app +if [ $? -ne 0 ]; then + echo "compile app code failed" + exit 1 +fi +infer +if [ $? -ne 0 ]; then + echo " execute inference failed" + exit 1 +fi +cal_metrics +if [ $? -ne 0 ]; then + echo "calculate metrics failed" + exit 1 +fi diff --git a/research/cv/pcb/scripts/run_standalone_train.sh b/research/cv/pcb/scripts/run_standalone_train.sh new file mode 100644 index 0000000000000000000000000000000000000000..bda8cfab77b5990e3cba8dce635be5d2f0af40bc --- /dev/null +++ b/research/cv/pcb/scripts/run_standalone_train.sh @@ -0,0 +1,122 @@ +#!/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. +# ============================================================================ + + +if [ $# != 4 ] && [ $# != 5 ] +then + echo "Usage: bash run_standalone_train.sh [MODEL_NAME] [DATASET_NAME] [DATASET_PATH] [CONFIG_PATH] [PRETRAINED_CKPT_PATH](optional)" +exit 1 +fi + + +get_real_path(){ + if [ "${1:0:1}" == "/" ]; then + echo "$1" + else + echo "$(realpath -m $PWD/$1)" + fi +} + +MODEL_NAME=$1 +DATASET_NAME=$2 +DATASET_PATH=$(get_real_path $3) +CONFIG_PATH=$(get_real_path $4) + +if [ $# == 5 ]; then + PRETRAINED_CKPT_PATH=$(get_real_path $5) +else + PRETRAINED_CKPT_PATH="" +fi + +if [ $MODEL_NAME != "PCB" ] && [ $MODEL_NAME != "RPP" ] +then + echo "error: MODEL_NAME=$MODEL_NAME is invalid, please choose from ['PCB','RPP']" +exit 1 +fi + +if [ $DATASET_NAME != "market" ] && [ $DATASET_NAME != "duke" ] && [ $DATASET_NAME != "cuhk03" ] +then + echo "error: DATASET_NAME=$DATASET_NAME is invalid, please choose from ['market','duke','cuhk03']" +exit 1 +fi + +if [ ! -d $DATASET_PATH ] +then + echo "error: DATASET_PATH=$DATASET_PATH is not a directory" +exit 1 +fi + + +if ( [ $MODEL_NAME = "PCB" ] && [ $DATASET_NAME = "market" ] ) || ( [ $MODEL_NAME = "PCB" ] && [ $DATASET_NAME = "duke" ] ) +then + if [ ! -f $CONFIG_PATH ] + then + echo "error: CONFIG_PATH=$CONFIG_PATH is not a file" + exit 1 + fi +else + if [ ! -d $CONFIG_PATH ] + then + echo "error: CONFIG_PATH=$CONFIG_PATH is not a directory" + exit 1 + fi +fi + +if [ $# == 5 ] && [ ! -f $PRETRAINED_CKPT_PATH ] +then + echo "error: PRETRAINED_CKPT_PATH=$PRETRAINED_CKPT_PATH is not a file" +exit 1 +fi + +export DEVICE_NUM=1 +export RANK_ID=0 +export RANK_SIZE=1 + +script_path=$(readlink -f "$0") +script_dir_path=$(dirname "${script_path}") + +LOG_SAVE_PATH=${script_dir_path}/output/log/${MODEL_NAME}/${DATASET_NAME}/train/ +CHECKPOINT_SAVE_PATH=${script_dir_path}/output/checkpoint/${MODEL_NAME}/${DATASET_NAME}/train/ + +if [ -d ${LOG_SAVE_PATH} ]; +then + rm -rf ${LOG_SAVE_PATH} +fi + +if [ -d ${CHECKPOINT_SAVE_PATH} ]; +then + rm -rf ${CHECKPOINT_SAVE_PATH} +fi + +if [ $MODEL_NAME = "PCB" ] && [ $DATASET_NAME = "market" ]; then + python ${script_dir_path}/../train.py --dataset_path=$DATASET_PATH --config_path=$CONFIG_PATH --checkpoint_file_path=$PRETRAINED_CKPT_PATH --output_path ${script_dir_path}/output/ +elif [ $MODEL_NAME = "PCB" ] && [ $DATASET_NAME = "duke" ]; then + python ${script_dir_path}/../train.py --dataset_path=$DATASET_PATH --config_path=$CONFIG_PATH --checkpoint_file_path=$PRETRAINED_CKPT_PATH --output_path ${script_dir_path}/output/ +elif [ $MODEL_NAME = "PCB" ] && [ $DATASET_NAME = "cuhk03" ]; then + python ${script_dir_path}/../train.py --dataset_path=$DATASET_PATH --config_path ${CONFIG_PATH}/train_PCB.yaml --checkpoint_file_path=$PRETRAINED_CKPT_PATH --output_path ${script_dir_path}/output/ + python ${script_dir_path}/../train.py --dataset_path=$DATASET_PATH --config_path ${CONFIG_PATH}/finetune_PCB.yaml --checkpoint_file_path ${CHECKPOINT_SAVE_PATH}/PCB-40_115.ckpt --output_path ${script_dir_path}/output/ +elif [ $MODEL_NAME = "RPP" ] && [ $DATASET_NAME = "market" ]; then + python ${script_dir_path}/../train.py --dataset_path=$DATASET_PATH --config_path ${CONFIG_PATH}/train_PCB.yaml --checkpoint_file_path=$PRETRAINED_CKPT_PATH --output_path ${script_dir_path}/output/ + python ${script_dir_path}/../train.py --dataset_path=$DATASET_PATH --config_path ${CONFIG_PATH}/train_RPP.yaml --checkpoint_file_path ${CHECKPOINT_SAVE_PATH}/PCB-20_202.ckpt --output_path ${script_dir_path}/output/ + python ${script_dir_path}/../train.py --dataset_path=$DATASET_PATH --config_path ${CONFIG_PATH}/finetune_RPP.yaml --checkpoint_file_path ${CHECKPOINT_SAVE_PATH}/RPP-45_202.ckpt --output_path ${script_dir_path}/output/ +elif [ $MODEL_NAME = "RPP" ] && [ $DATASET_NAME = "duke" ]; then + python ${script_dir_path}/../train.py --dataset_path=$DATASET_PATH --config_path ${CONFIG_PATH}/train_PCB.yaml --checkpoint_file_path=$PRETRAINED_CKPT_PATH --output_path ${script_dir_path}/output/ + python ${script_dir_path}/../train.py --dataset_path=$DATASET_PATH --config_path ${CONFIG_PATH}/train_RPP.yaml --checkpoint_file_path ${CHECKPOINT_SAVE_PATH}/PCB-20_258.ckpt --output_path ${script_dir_path}/output/ +else + python ${script_dir_path}/../train.py --dataset_path=$DATASET_PATH --config_path ${CONFIG_PATH}/train_PCB.yaml --checkpoint_file_path=$PRETRAINED_CKPT_PATH --output_path ${script_dir_path}/output/ + python ${script_dir_path}/../train.py --dataset_path=$DATASET_PATH --config_path ${CONFIG_PATH}/train_RPP.yaml --checkpoint_file_path ${CHECKPOINT_SAVE_PATH}/PCB-40_115.ckpt --output_path ${script_dir_path}/output/ + python ${script_dir_path}/../train.py --dataset_path=$DATASET_PATH --config_path ${CONFIG_PATH}/finetune_RPP.yaml --checkpoint_file_path ${CHECKPOINT_SAVE_PATH}/RPP-45_115.ckpt --output_path ${script_dir_path}/output/ +fi diff --git a/research/cv/pcb/src/__init__.py b/research/cv/pcb/src/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..ca9b0ba5b19b49918e9cf857e4873c0d9f837f10 --- /dev/null +++ b/research/cv/pcb/src/__init__.py @@ -0,0 +1,15 @@ +# 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. +# ============================================================================ +"""__init__.py""" diff --git a/research/cv/pcb/src/dataset.py b/research/cv/pcb/src/dataset.py new file mode 100644 index 0000000000000000000000000000000000000000..7ec99620c15e68ba5f8550a854ddbf55e6641d21 --- /dev/null +++ b/research/cv/pcb/src/dataset.py @@ -0,0 +1,142 @@ +# 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. +# ============================================================================ + + +""" +Produce the dataset +""" +import os +import multiprocessing +import time + +import numpy as np + +from mindspore.communication.management import init, get_rank, get_group_size +from mindspore.mindrecord import FileWriter +import mindspore.common.dtype as mstype +import mindspore.dataset as ds +import mindspore.dataset.vision.c_transforms as C +import mindspore.dataset.transforms.c_transforms as C2 +from mindspore.dataset.vision import Inter + +from src import datasets +from src.model_utils.config import config + + +def create_mindrecord_file(data, mindrecord_file, file_num=1): + """Create MindRecord file.""" + writer = FileWriter(mindrecord_file, file_num) + schema_json = { + "image": {"type": "bytes"}, + "fid": {"type": "int32"}, + "pid": {"type": "int32"}, + "camid": {"type": "int32"} + } + writer.add_schema(schema_json, "schema_json") + for fpath, fid, pid, camid in data: + with open(fpath, 'rb') as f: + img = f.read() + row = {"image": img, "fid": fid, "pid": pid, "camid": camid} + writer.write_raw_data([row]) + writer.commit() + +def create_dataset(dataset_name, dataset_path, subset_name, batch_size=32, num_parallel_workers=4, distribute=False): + """Create MindRecord Dataset""" + ds.config.set_seed(1) + subset = datasets.create(dataset_name, root=dataset_path, subset_name=subset_name) + data = subset.data + mindrecord_dir = os.path.join(config.mindrecord_dir, dataset_name) + mindrecord_file = os.path.join(mindrecord_dir, subset_name + ".mindrecord") + if not os.path.exists(mindrecord_file): + if not os.path.isdir(mindrecord_dir): + os.makedirs(mindrecord_dir) + create_mindrecord_file(data, mindrecord_file) + while not os.path.exists(mindrecord_file + ".db"): + time.sleep(5) + device_num, rank_id = _get_rank_info(distribute) + num_parallel_workers = get_num_parallel_workers(num_parallel_workers) + is_train = subset_name == "train" + if device_num == 1: + data_set = ds.MindDataset(mindrecord_file, columns_list=["image", "fid", "pid", "camid"], \ +num_parallel_workers=num_parallel_workers, shuffle=is_train) + else: + data_set = ds.MindDataset(mindrecord_file, columns_list=["image", "fid", "pid", "camid"], \ +num_shards=device_num, shard_id=rank_id, num_parallel_workers=num_parallel_workers, shuffle=is_train) + #map operations on images + decode_op = C.Decode() + resize_op = C.Resize([384, 128], Inter.LINEAR) + flip_op = C.RandomHorizontalFlip(prob=0.5) + rescale_op = C.Rescale(1.0 / 255.0, 0.0) + normalize_op = C.Normalize(mean=[0.485, 0.456, 0.406], + std=[0.229, 0.224, 0.225]) + swap_op = C.HWC2CHW() + trans = [] + if is_train: + trans += [decode_op, + resize_op, + flip_op, + rescale_op, + normalize_op, + swap_op] + else: + trans += [decode_op, + resize_op, + rescale_op, + normalize_op, + swap_op] + data_set = data_set.map(operations=trans, input_columns=["image"], \ +num_parallel_workers=num_parallel_workers) + #map operations on labels + type_cast_op = C2.TypeCast(mstype.int32) + squeeze_op = np.squeeze + trans = [type_cast_op, squeeze_op] + data_set = data_set.map(operations=trans, input_columns=["fid"], \ +num_parallel_workers=num_parallel_workers) + data_set = data_set.map(operations=trans, input_columns=["pid"], \ +num_parallel_workers=num_parallel_workers) + data_set = data_set.map(operations=trans, input_columns=["camid"], \ +num_parallel_workers=num_parallel_workers) + # apply batch operations + data_set = data_set.batch(batch_size, drop_remainder=is_train) + return data_set, subset + +def _get_rank_info(distribute): + """get rank info""" + if distribute: + init() + rank_id = get_rank() + device_num = get_group_size() + else: + rank_id = 0 + device_num = 1 + return device_num, rank_id + +def get_num_parallel_workers(num_parallel_workers): + """ + Get num_parallel_workers used in dataset operations. + If num_parallel_workers > the real CPU cores number, set num_parallel_workers = the real CPU cores number. + """ + cores = multiprocessing.cpu_count() + if isinstance(num_parallel_workers, int): + if cores < num_parallel_workers: + print("The num_parallel_workers {} is set too large, now set it {}".format(num_parallel_workers, cores)) + num_parallel_workers = cores + else: + print("The num_parallel_workers {} is invalid, now set it {}".format(num_parallel_workers, min(cores, 8))) + num_parallel_workers = min(cores, 8) + return num_parallel_workers + +if __name__ == "__main__": + pass diff --git a/research/cv/pcb/src/datasets/__init__.py b/research/cv/pcb/src/datasets/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..5d90c1944195275c7d7a5414b89a6dfc7596c1e5 --- /dev/null +++ b/research/cv/pcb/src/datasets/__init__.py @@ -0,0 +1,47 @@ +# 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. +# ============================================================================ +"""__init__.py""" + +from .market import Market +from .duke import Duke +from .cuhk03 import CUHK03 + +__factory = { + 'market': Market, + 'duke': Duke, + 'cuhk03': CUHK03 +} + + +def names(): + return sorted(__factory.keys()) + + +def create(dataset_name, root, subset_name, *args, **kwargs): + """ + Create a dataset instance. + + Parameters + ---------- + dataset_name : str + The dataset name. Can be one of 'market', 'duke', 'cuhk03' + root : str + The path to the dataset directory. + subset_name : str + The subset name. Can be one of "train", "query", "gallery" + """ + if dataset_name not in __factory: + raise KeyError("Unknown dataset:", dataset_name) + return __factory[dataset_name](root, subset_name, *args, **kwargs) diff --git a/research/cv/pcb/src/datasets/cuhk03.py b/research/cv/pcb/src/datasets/cuhk03.py new file mode 100644 index 0000000000000000000000000000000000000000..f502df9544d7a535dabced2ba0e7157def19573b --- /dev/null +++ b/research/cv/pcb/src/datasets/cuhk03.py @@ -0,0 +1,130 @@ +# 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. +# ============================================================================ +"""cuhk03.py""" + +import os +import os.path as osp +import time + +import h5py +import imageio +from scipy.io import loadmat + +class CUHK03: + """ + Class for processing CUHK03 dataset + """ + def __init__(self, root, subset_name): + """ + :param root: path of CUHK03 dataset + :param subset_name: choose from ['train', 'query', 'gallery'] + """ + self.root = root + self.images_dir = osp.join(root, "detected_images") + split_new_det_mat_path = osp.join(root, "cuhk03_new_protocol_config_detected.mat") + self.split_dict = loadmat(split_new_det_mat_path) + self.subset_name = subset_name + self.data = [] + self.num_ids = 0 + self.relabel = subset_name == 'train' + self.detected_images_dir = osp.join(self.root, "detected_images") + if not osp.exists(self.detected_images_dir): + os.makedirs(self.detected_images_dir) + self.prepare_detected_images() + while len(os.listdir(self.detected_images_dir)) != 14097: + time.sleep(5) + self.load() + + def _deref(self, mat, ref): + """_deref""" + return mat[ref][:].T + + def _process_images(self, mat, img_refs, campid, pid, save_dir): + """_process_images""" + img_paths = [] # Note: some persons only have images for one view + for imgid, img_ref in enumerate(img_refs): + img = self._deref(mat, img_ref) + if img.size == 0 or img.ndim < 3: + continue # skip empty cell + # images are saved with the following format, index-1 (ensure uniqueness) + # campid: index of camera pair (1-5) --full name: camera pair id + # pid: index of person in 'campid'-th camera pair + # viewid: index of view, {1, 2} + # imgid: index of image, (1-10) + viewid = 1 if imgid < 5 else 2 + img_name = '{:01d}_{:03d}_{:01d}_{:02d}.png'.format( + campid + 1, pid + 1, viewid, imgid + 1 + ) + img_path = osp.join(save_dir, img_name) + if not osp.isfile(img_path): + imageio.imwrite(img_path, img) + img_paths.append(img_path) + return img_paths + + def prepare_detected_images(self): + """prepare_detected_images""" + raw_mat_path = osp.join(self.root, "cuhk-03.mat") + print( + 'Extract image data from "{}" and save as png'.format( + raw_mat_path + ) + ) + mat = h5py.File(raw_mat_path, 'r') + print('Processing detected images ...') + for campid, camp_ref in enumerate(mat["detected"][0]): + camp = self._deref(mat, camp_ref) + num_pids = camp.shape[0] + for pid in range(num_pids): + img_paths = self._process_images( + mat, camp[pid, :], campid, pid, self.detected_images_dir + ) + assert img_paths != [], \ + 'campid{}-pid{} has no images'.format(campid, pid) + print( + '- done camera pair {} with {} identities'.format( + campid + 1, num_pids + ) + ) + + def preprocess(self, filelist, pids, idxs, relabel): + """preprocess""" + ret = [] + unique_pids = set() + pid2label = dict() + if relabel: + tmp_pids = set(pids[idxs]) + pid2label = {pid: label for label, pid in enumerate(tmp_pids)} + for fid, idx in enumerate(idxs): + img_name = filelist[idx][0] + fpath = osp.join(self.images_dir, img_name) + camid = int(img_name.split('_')[2]) - 1 + pid = pids[idx] + if relabel: + pid = pid2label[pid] + ret.append((fpath, fid, int(pid), camid)) + unique_pids.add(pid) + return ret, len(unique_pids) + + def load(self): + """load""" + pids = self.split_dict['labels'].flatten() + filelist = self.split_dict['filelist'].flatten() + idxs = self.split_dict[self.subset_name + '_idx'].flatten() - 1 + self.data, self.num_ids = self.preprocess(filelist, pids, idxs, self.relabel) + print(self.__class__.__name__, "dataset loaded") + print(" # subset | # ids | # images") + print(" ---------------------------") + print(" {:8} | {:5d} | {:8d}" + .format(self.subset_name, self.num_ids, len(self.data))) diff --git a/research/cv/pcb/src/datasets/duke.py b/research/cv/pcb/src/datasets/duke.py new file mode 100644 index 0000000000000000000000000000000000000000..a5ded6f081efcc341a72225ad2548d66227aec69 --- /dev/null +++ b/research/cv/pcb/src/datasets/duke.py @@ -0,0 +1,69 @@ +# 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. +# ============================================================================ +"""duke.py""" + +import os.path as osp +from glob import glob +import re + +class Duke: + """Class for processing DukeMTMC-reID dataset""" + def __init__(self, root, subset_name): + """ + :param root: path of DukeMTMC-reID dataset + :param subset_name: choose from ['train', 'query', 'gallery'] + """ + self.name2path = {'train': 'bounding_box_train', + 'query': 'query', + 'gallery': 'bounding_box_test'} + self.images_dir = osp.join(root) + self.subset_name = subset_name + self.subset_path = self.name2path[subset_name] + self.data = [] + self.num_ids = 0 + self.relabel = subset_name == 'train' + self.load() + + def preprocess(self, path, relabel=True): + """preprocess""" + pattern = re.compile(r'([-\d]+)_c(\d)') + all_pids = {} + ret = [] + fpaths = sorted(glob(osp.join(self.images_dir, path, '*.jpg'))) + fid = 0 + for fpath in fpaths: + fname = osp.basename(fpath) + pid, cam = map(int, pattern.search(fname).groups()) + if pid == -1: continue + if relabel: + if pid not in all_pids: + all_pids[pid] = len(all_pids) + else: + if pid not in all_pids: + all_pids[pid] = pid + pid = all_pids[pid] + cam -= 1 + ret.append((fpath, fid, pid, cam)) + fid += 1 + return ret, int(len(all_pids)) + + def load(self): + """load""" + self.data, self.num_ids = self.preprocess(self.subset_path, self.relabel) + print(self.__class__.__name__, "dataset loaded") + print(" # subset | # ids | # images") + print(" ---------------------------") + print(" {:8} | {:5d} | {:8d}" + .format(self.subset_name, self.num_ids, len(self.data))) diff --git a/research/cv/pcb/src/datasets/market.py b/research/cv/pcb/src/datasets/market.py new file mode 100644 index 0000000000000000000000000000000000000000..3bbb1ffe6662c9ad20740785e4b9b08806207b39 --- /dev/null +++ b/research/cv/pcb/src/datasets/market.py @@ -0,0 +1,69 @@ +# 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. +# ============================================================================ +"""market.py""" + +import os.path as osp +from glob import glob +import re + +class Market: + """Class for processing Market-1501 dataset""" + def __init__(self, root, subset_name): + """ + :param root: path of Market-1501 dataset + :param subset_name: choose from ['train', 'query', 'gallery'] + """ + self.name2path = {'train': 'bounding_box_train', + 'query': 'query', + 'gallery': 'bounding_box_test'} + self.images_dir = osp.join(root) + self.subset_name = subset_name + self.subset_path = self.name2path[subset_name] + self.data = [] + self.num_ids = 0 + self.relabel = subset_name == 'train' + self.load() + + def preprocess(self, path, relabel=True): + """preprocess""" + pattern = re.compile(r'([-\d]+)_c(\d)') + all_pids = {} + ret = [] + fpaths = sorted(glob(osp.join(self.images_dir, path, '*.jpg'))) + fid = 0 + for fpath in fpaths: + fname = osp.basename(fpath) + pid, cam = map(int, pattern.search(fname).groups()) + if pid == -1: continue + if relabel: + if pid not in all_pids: + all_pids[pid] = len(all_pids) + else: + if pid not in all_pids: + all_pids[pid] = pid + pid = all_pids[pid] + cam -= 1 + ret.append((fpath, fid, pid, cam)) + fid += 1 + return ret, int(len(all_pids)) + + def load(self): + """load""" + self.data, self.num_ids = self.preprocess(self.subset_path, self.relabel) + print(self.__class__.__name__, "dataset loaded") + print(" # subset | # ids | # images") + print(" ---------------------------") + print(" {:8} | {:5d} | {:8d}" + .format(self.subset_name, self.num_ids, len(self.data))) diff --git a/research/cv/pcb/src/eval_callback.py b/research/cv/pcb/src/eval_callback.py new file mode 100644 index 0000000000000000000000000000000000000000..5fc8283b9e2f27492b04e96461345fb23225d21a --- /dev/null +++ b/research/cv/pcb/src/eval_callback.py @@ -0,0 +1,88 @@ +# 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. +# ============================================================================ + + +"""Evaluation callback when training""" + +import os +from mindspore import save_checkpoint +from mindspore.train.callback import Callback +from src.model_utils.config import config + +class EvalCallBack(Callback): + """ + Evaluation callback when training. + + Args: + eval_function (function): evaluation function. + eval_param_dict (dict): evaluation parameters' configure dict. + interval (int): run evaluation interval, default is 1. + eval_start_epoch (int): evaluation start epoch, default is 1. + save_best_ckpt (bool): Whether to save best checkpoint, default is True. + besk_ckpt_name (str): bast checkpoint name, default is `best.ckpt`. + metrics_name (str): evaluation metrics name, default is (`mAP`,`CMC`). + + Returns: + None + + Examples: + >>> EvalCallBack(eval_function, eval_param_dict) + """ + + def __init__(self, eval_function, eval_param_dict, interval=1, eval_start_epoch=1, save_best_ckpt=True, + ckpt_directory="./", best_ckpt_name="best.ckpt", metrics_name=("mAP", "CMC"), cmc_topk=(1, 5, 10)): + super(EvalCallBack, self).__init__() + self.eval_param_dict = eval_param_dict + self.eval_function = eval_function + self.eval_start_epoch = eval_start_epoch + if interval < 1: + raise ValueError("interval should >= 1.") + self.interval = interval + self.save_best_ckpt = save_best_ckpt + self.best_mAP = 0 + self.best_cmc_scores = None + self.best_epoch = 0 + if not os.path.isdir(ckpt_directory): + os.makedirs(ckpt_directory) + self.best_ckpt_path = os.path.join(ckpt_directory, best_ckpt_name) + self.metrics_name = metrics_name + self.cmc_topk = cmc_topk + + def epoch_end(self, run_context): + """Callback when epoch end.""" + cb_params = run_context.original_args() + cur_epoch = cb_params.cur_epoch_num + if cur_epoch >= self.eval_start_epoch and (cur_epoch - self.eval_start_epoch) % self.interval == 0: + mAP, cmc_scores = self.eval_function(self.eval_param_dict) + print('Mean AP: {:4.1%}'.format(mAP), flush=True) + print('CMC Scores{:>12}'.format(config.dataset_name), flush=True) + for k in self.cmc_topk: + print(' top-{:<4}{:12.1%}'.format(k, cmc_scores[config.dataset_name][k - 1]), flush=True) + if mAP >= self.best_mAP: + self.best_mAP = mAP + self.best_cmc_scores = cmc_scores + self.best_epoch = cur_epoch + print("update best mAP: {}".format(mAP), flush=True) + if self.save_best_ckpt: + save_checkpoint(cb_params.train_network, self.best_ckpt_path) + print("update best checkpoint at: {}".format(self.best_ckpt_path), flush=True) + + def end(self, run_context): + print("End training, the best epoch is {}".format(self.best_epoch), flush=True) + print("Best result:", flush=True) + print('Mean AP: {:4.1%}'.format(self.best_mAP), flush=True) + print('CMC Scores{:>12}'.format(config.dataset_name), flush=True) + for k in self.cmc_topk: + print(' top-{:<4}{:12.1%}'.format(k, self.best_cmc_scores[config.dataset_name][k - 1]), flush=True) diff --git a/research/cv/pcb/src/eval_utils.py b/research/cv/pcb/src/eval_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..80f692d92e680f9d9d98592a073857c6d70535b1 --- /dev/null +++ b/research/cv/pcb/src/eval_utils.py @@ -0,0 +1,139 @@ +# 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. +# ============================================================================ +"""eval_utils.py""" + +import time +from collections import OrderedDict +import numpy as np + +from src.model_utils.config import config +from src.meters import AverageMeter + +def apply_eval(eval_param_dict): + """apply eval""" + net = eval_param_dict["net"] + net.set_train(False) + query_dataset = eval_param_dict["query_dataset"] + gallery_dataset = eval_param_dict["gallery_dataset"] + query_set = eval_param_dict["query_set"] + gallery_set = eval_param_dict["gallery_set"] + print('extracting query features\n') + query_features, _ = extract_features(net, query_dataset) + print('extracting gallery features\n') + gallery_features, _ = extract_features(net, gallery_dataset) + x = [query_features[fid] for _, fid, _, _ in query_set] + x = list(map(lambda item: np.expand_dims(item, 0), x)) + x = np.concatenate(x, axis=0) + y = [gallery_features[fid] for _, fid, _, _ in gallery_set] + y = list(map(lambda item: np.expand_dims(item, 0), y)) + y = np.concatenate(y, axis=0) + m, n = x.shape[0], y.shape[0] + query_feature = x.reshape(m, -1) + gallery_feature = y.reshape(n, -1) + query_label = [pid for _, _, pid, _ in query_set] + gallery_label = [pid for _, _, pid, _ in gallery_set] + query_cam = [cam for _, _, _, cam in query_set] + gallery_cam = [cam for _, _, _, cam in gallery_set] + query_label = np.asarray(query_label) + gallery_label = np.asarray(gallery_label) + query_cam = np.asarray(query_cam) + gallery_cam = np.asarray(gallery_cam) + CMC = np.zeros((len(gallery_label),)) + ap = 0.0 + for i in range(len(query_label)): + ap_tmp, CMC_tmp = evaluate(query_feature[i], query_label[i], query_cam[i], \ +gallery_feature, gallery_label, gallery_cam) + if CMC_tmp[0] == -1: + continue + CMC = CMC + CMC_tmp + ap += ap_tmp + CMC = CMC / len(query_label) + cmc_scores = {config.dataset_name: CMC} + mAP = ap / len(query_label) + return mAP, cmc_scores + +def extract_features(model, dataset, print_freq=10): + """extract query features/ gallery features""" + batch_time = AverageMeter() + data_time = AverageMeter() + features = OrderedDict() + labels = OrderedDict() + end = time.time() + for i, (imgs, fids, pids, _) in enumerate(dataset): + data_time.update(time.time() - end) + _, g_features, h_features = model(imgs) + features_to_use = None + if config.use_G_feature: + features_to_use = g_features + else: #use H feature + features_to_use = h_features + for fid, feature, pid in zip(fids, features_to_use, pids): + fid = int(fid.asnumpy()) + features[fid] = feature.asnumpy() + labels[fid] = pid + batch_time.update(time.time() - end) + end = time.time() + if (i + 1) % print_freq == 0: + print('Extract Features: [{}/{}]\t' + 'Time {:.3f} ({:.3f})\t' + 'Data {:.3f} ({:.3f})\t' + .format(i + 1, dataset.get_dataset_size(), + batch_time.val, batch_time.avg, + data_time.val, data_time.avg)) + return features, labels + +def evaluate(qf, ql, qc, gf, gl, gc): + """evaluate""" + query = qf + score = None + index = None + score = np.dot(gf, query) + # predict index + index = np.argsort(score) # from small to large + index = index[::-1] + query_index = np.argwhere(gl == ql) + camera_index = np.argwhere(gc == qc) + good_index = np.setdiff1d(query_index, camera_index, assume_unique=True) + junk_index1 = np.argwhere(gl == -1) + junk_index2 = np.intersect1d(query_index, camera_index) + junk_index = np.append(junk_index2, junk_index1) + CMC_tmp = compute_mAP(index, good_index, junk_index) + return CMC_tmp + +def compute_mAP(index, good_index, junk_index): + """compute mAP""" + ap = 0 + cmc = np.zeros((len(index),)) + if good_index.size == 0: # if empty + cmc[0] = -1 + return ap, cmc + # remove junk_index + mask = np.in1d(index, junk_index, invert=True) + index = index[mask] + # find good_index index + ngood = len(good_index) + mask = np.in1d(index, good_index) + rows_good = np.argwhere(mask) + rows_good = rows_good.flatten() + cmc[rows_good[0]:] = 1 + for i in range(ngood): + d_recall = 1.0 / ngood + precision = (i + 1) * 1.0 / (rows_good[i] + 1) + if rows_good[i] != 0: + old_precision = i * 1.0 / rows_good[i] + else: + old_precision = 1.0 + ap = ap + d_recall * (old_precision + precision) / 2 + return ap, cmc diff --git a/research/cv/pcb/src/logging.py b/research/cv/pcb/src/logging.py new file mode 100644 index 0000000000000000000000000000000000000000..6d97036f30968ff69d935f4d952e8229ee122cbd --- /dev/null +++ b/research/cv/pcb/src/logging.py @@ -0,0 +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. +# ============================================================================ +"""logging.py""" + +import os +import sys + +class Logger: + """Logger""" + def __init__(self, fpath=None): + self.console = sys.stdout + self.file = None + if fpath is not None: + if os.path.exists(fpath): + self.file = open(fpath, 'a') + else: + 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/research/cv/pcb/src/lr_generator.py b/research/cv/pcb/src/lr_generator.py new file mode 100644 index 0000000000000000000000000000000000000000..a3189e6fc92925b58e6fdc0f4a1c098fd7092772 --- /dev/null +++ b/research/cv/pcb/src/lr_generator.py @@ -0,0 +1,38 @@ +# 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. +# ============================================================================ + +"""learning rate generator""" +import numpy as np +from mindspore import Tensor +from src.model_utils.config import config + + +def get_lr(lr_init, lr_max, total_steps, warmup_steps, decay_steps): + """get the learning rate of each step""" + decay_step_index = list(range(decay_steps, total_steps, decay_steps)) + decay_step_index.append(total_steps) # pivot for convenience + lr_each_step = [] + for i in range(total_steps): + if i < warmup_steps: + lr = lr_init + (lr_max - lr_init) * i / warmup_steps + else: + for j in range(len(decay_step_index)): + if i < decay_step_index[j]: + lr = lr_max * pow(config.decay_rate, j) + break + lr_each_step.append(lr) + lr_each_step = np.array(lr_each_step).astype(np.float32) + lr_each_step = Tensor(lr_each_step) + return lr_each_step diff --git a/research/cv/pcb/src/meters.py b/research/cv/pcb/src/meters.py new file mode 100644 index 0000000000000000000000000000000000000000..8f18727b469da69cb9b9388e7d8411ffe84baf5c --- /dev/null +++ b/research/cv/pcb/src/meters.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. +# ============================================================================ +"""meters.py""" + + +from __future__ import absolute_import + + +class AverageMeter: + """Computes and stores the average and current value""" + def __init__(self): + self.val = 0 + self.avg = 0 + self.sum = 0 + self.count = 0 + + 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 diff --git a/research/cv/pcb/src/model_utils/config.py b/research/cv/pcb/src/model_utils/config.py new file mode 100644 index 0000000000000000000000000000000000000000..51f763133f7f1cd2971a85963a24e90fa5672a7b --- /dev/null +++ b/research/cv/pcb/src/model_utils/config.py @@ -0,0 +1,130 @@ +# 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. +# ============================================================================ + + + +"""Parse arguments""" + +import os +import ast +import argparse +from pprint import pformat, pprint +import yaml + +class Config: + """ + Configuration namespace. Convert dictionary to members. + """ + def __init__(self, cfg_dict): + for k, v in cfg_dict.items(): + if isinstance(v, (list, tuple)): + setattr(self, k, [Config(x) if isinstance(x, dict) else x for x in v]) + else: + setattr(self, k, Config(v) if isinstance(v, dict) else v) + + def __str__(self): + return pformat(self.__dict__) + + def __repr__(self): + return self.__str__() + + +def parse_cli_to_yaml(parser, cfg, helper=None, choices=None, cfg_path="base_config.yaml"): + """ + Parse command line arguments to the configuration according to the default yaml. + + Args: + parser: Parent parser. + cfg: Base configuration. + helper: Helper description. + cfg_path: Path to the default yaml config. + """ + parser = argparse.ArgumentParser(description="[REPLACE THIS at config.py]", + parents=[parser]) + helper = {} if helper is None else helper + choices = {} if choices is None else choices + for item in cfg: + if not isinstance(cfg[item], list) and not isinstance(cfg[item], dict): + help_description = helper[item] if item in helper else "Please reference to {}".format(cfg_path) + choice = choices[item] if item in choices else None + if isinstance(cfg[item], bool): + parser.add_argument("--" + item, type=ast.literal_eval, default=cfg[item], choices=choice, + help=help_description) + else: + parser.add_argument("--" + item, type=type(cfg[item]), default=cfg[item], choices=choice, + help=help_description) + args = parser.parse_args() + return args + + +def parse_yaml(yaml_path): + """ + Parse the yaml config file. + + Args: + yaml_path: Path to the yaml config. + """ + with open(yaml_path, 'r') as fin: + try: + cfgs = yaml.load_all(fin.read(), Loader=yaml.FullLoader) + cfgs = [x for x in cfgs] + if len(cfgs) == 1: + cfg_helper = {} + cfg = cfgs[0] + cfg_choices = {} + elif len(cfgs) == 2: + cfg, cfg_helper = cfgs + cfg_choices = {} + elif len(cfgs) == 3: + cfg, cfg_helper, cfg_choices = cfgs + else: + raise ValueError("At most 3 docs (config description for help, choices) are supported in config yaml") + print(cfg_helper) + except: + raise ValueError("Failed to parse yaml") + return cfg, cfg_helper, cfg_choices + + +def merge(args, cfg): + """ + Merge the base config from yaml file and command line arguments. + + Args: + args: Command line arguments. + cfg: Base configuration. + """ + args_var = vars(args) + for item in args_var: + cfg[item] = args_var[item] + return cfg + + +def get_config(): + """ + Get Config according to the yaml file and cli arguments. + """ + parser = argparse.ArgumentParser(description="default name", add_help=False) + current_dir = os.path.dirname(os.path.abspath(__file__)) + parser.add_argument("--config_path", type=str, default=os.path.join(current_dir, \ + "../../config/base_config.yaml"), help="Config file path") + path_args, _ = parser.parse_known_args() + default, helper, choices = parse_yaml(path_args.config_path) + args = parse_cli_to_yaml(parser=parser, cfg=default, helper=helper, choices=choices, cfg_path=path_args.config_path) + final_config = merge(args, default) + pprint(final_config) + print("Please check the above information for the configurations", flush=True) + return Config(final_config) + +config = get_config() diff --git a/research/cv/pcb/src/model_utils/device_adapter.py b/research/cv/pcb/src/model_utils/device_adapter.py new file mode 100644 index 0000000000000000000000000000000000000000..94a13cb1327339cfbbe45c5eb571f86954b397db --- /dev/null +++ b/research/cv/pcb/src/model_utils/device_adapter.py @@ -0,0 +1,28 @@ +# 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. +# ============================================================================ + + +"""Device adapter for ModelArts""" + +from src.model_utils.config import config + +if config.enable_modelarts: + from src.model_utils.moxing_adapter import get_device_id, get_device_num, get_rank_id, get_job_id +else: + from src.model_utils.local_adapter import get_device_id, get_device_num, get_rank_id, get_job_id + +__all__ = [ + "get_device_id", "get_device_num", "get_rank_id", "get_job_id" +] diff --git a/research/cv/pcb/src/model_utils/local_adapter.py b/research/cv/pcb/src/model_utils/local_adapter.py new file mode 100644 index 0000000000000000000000000000000000000000..76df3911a3bc28e5256a930f4abcb2b405c67109 --- /dev/null +++ b/research/cv/pcb/src/model_utils/local_adapter.py @@ -0,0 +1,37 @@ +# 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. +# ============================================================================ + + +"""Local adapter""" + +import os + +def get_device_id(): + device_id = os.getenv('DEVICE_ID', '0') + return int(device_id) + + +def get_device_num(): + device_num = os.getenv('RANK_SIZE', '1') + return int(device_num) + + +def get_rank_id(): + global_rank_id = os.getenv('RANK_ID', '0') + return int(global_rank_id) + + +def get_job_id(): + return "Local Job" diff --git a/research/cv/pcb/src/model_utils/moxing_adapter.py b/research/cv/pcb/src/model_utils/moxing_adapter.py new file mode 100644 index 0000000000000000000000000000000000000000..7095c178a997f7f40794aa04885dd94e4be59c04 --- /dev/null +++ b/research/cv/pcb/src/model_utils/moxing_adapter.py @@ -0,0 +1,117 @@ +# 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. +# ============================================================================ + + + +"""Moxing adapter for ModelArts""" + +import os +import functools +from mindspore import context +from src.model_utils.config import config + +_global_sync_count = 0 + +def get_device_id(): + device_id = os.getenv('DEVICE_ID', '0') + return int(device_id) + + +def get_device_num(): + device_num = os.getenv('RANK_SIZE', '1') + return int(device_num) + + +def get_rank_id(): + global_rank_id = os.getenv('RANK_ID', '0') + return int(global_rank_id) + + +def get_job_id(): + job_id = os.getenv('JOB_ID') + job_id = job_id if job_id != "" else "default" + return job_id + +def sync_data(from_path, to_path): + """ + Download data from remote obs to local directory if the first url is remote url and the second one is local path + Upload data from local directory to remote obs in contrast. + """ + import moxing as mox + import time + global _global_sync_count + sync_lock = "/tmp/copy_sync.lock" + str(_global_sync_count) + _global_sync_count += 1 + + # Each server contains 8 devices as most. + if get_device_id() % min(get_device_num(), 8) == 0 and not os.path.exists(sync_lock): + print("from path: ", from_path) + print("to path: ", to_path) + mox.file.copy_parallel(from_path, to_path) + print("===finish data synchronization===") + try: + os.mknod(sync_lock) + except IOError: + pass + print("===save flag===") + + while True: + if os.path.exists(sync_lock): + break + time.sleep(1) + + print("Finish sync data from {} to {}.".format(from_path, to_path)) + + +def moxing_wrapper(pre_process=None, post_process=None): + """ + Moxing wrapper to download dataset and upload outputs. + """ + def wrapper(run_func): + @functools.wraps(run_func) + def wrapped_func(*args, **kwargs): + # Download data from data_url + if config.enable_modelarts: + if config.data_url: + sync_data(config.data_url, config.dataset_path) + print("Dataset downloaded: ", os.listdir(config.dataset_path)) + if config.checkpoint_url: + sync_data(config.checkpoint_url, config.load_path) + print("Preload downloaded: ", os.listdir(config.load_path)) + if config.train_url: + sync_data(config.train_url, config.output_path) + print("Workspace downloaded: ", os.listdir(config.output_path)) + + context.set_context(save_graphs_path=os.path.join(config.output_path, str(get_rank_id()))) + config.device_num = get_device_num() + config.device_id = get_device_id() + if not os.path.exists(config.output_path): + os.makedirs(config.output_path) + + if pre_process: + pre_process() + + run_func(*args, **kwargs) + + # Upload data to train_url + if config.enable_modelarts: + if post_process: + post_process() + + if config.train_url: + print("Start to copy output directory") + sync_data(config.output_path, config.train_url) + return wrapped_func + return wrapper diff --git a/research/cv/pcb/src/pcb.py b/research/cv/pcb/src/pcb.py new file mode 100644 index 0000000000000000000000000000000000000000..85fd0839c647cf062e495a90fa81afb29c2942ec --- /dev/null +++ b/research/cv/pcb/src/pcb.py @@ -0,0 +1,139 @@ +# 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. +# ============================================================================ +"""pcb.py""" + +import mindspore.nn as nn +from mindspore.common.initializer import HeNormal, Normal, Constant + +import mindspore.ops as ops + +from src.model_utils.config import config +from src.resnet import resnet50 + +class PCB(nn.Cell): + """PCB Model""" + def __init__(self, num_classes): + super(PCB, self).__init__() + self.part = 6 + self.num_classes = num_classes + resnet = resnet50(1000) + self.base = resnet + self.avgpool = ops.AvgPool(pad_mode="valid", kernel_size=(4, 8), strides=(4, 8)) + self.dropout = nn.Dropout(keep_prob=0.5) + self.local_conv = nn.Conv2d(2048, 256, kernel_size=1, has_bias=False, \ +pad_mode="valid", weight_init=HeNormal(mode="fan_out")) + self.feat_bn2d = nn.BatchNorm2d(num_features=256) + self.relu = ops.ReLU() + self.expandDims = ops.ExpandDims() + self.norm = nn.Norm(axis=1) + self.split = ops.Split(2, 6) + # define 6 classifiers + self.instance0 = nn.Dense(256, self.num_classes, weight_init=Normal(sigma=0.001), bias_init=Constant(0)) + self.instance1 = nn.Dense(256, self.num_classes, weight_init=Normal(sigma=0.001), bias_init=Constant(0)) + self.instance2 = nn.Dense(256, self.num_classes, weight_init=Normal(sigma=0.001), bias_init=Constant(0)) + self.instance3 = nn.Dense(256, self.num_classes, weight_init=Normal(sigma=0.001), bias_init=Constant(0)) + self.instance4 = nn.Dense(256, self.num_classes, weight_init=Normal(sigma=0.001), bias_init=Constant(0)) + self.instance5 = nn.Dense(256, self.num_classes, weight_init=Normal(sigma=0.001), bias_init=Constant(0)) + + def construct(self, x): + """Forward propagation""" + x = self.base.conv1(x) + x = self.base.bn1(x) + x = self.base.relu(x) + x = self.base.pad(x) + x = self.base.maxpool(x) + x = self.base.layer1(x) + x = self.base.layer2(x) + x = self.base.layer3(x) + x = self.base.layer4(x) + x = self.avgpool(x) + g_feature = x / (self.expandDims(self.norm(x), 1)).expand_as(x) + if self.training: + x = self.dropout(x) + x = self.local_conv(x) + h_feature = x / (self.expandDims(self.norm(x), 1)).expand_as(x) + x = self.feat_bn2d(x) + x = self.relu(x) + x = self.split(x) + x0 = x[0].view(x[0].shape[0], -1) + x1 = x[1].view(x[1].shape[0], -1) + x2 = x[2].view(x[2].shape[0], -1) + x3 = x[3].view(x[3].shape[0], -1) + x4 = x[4].view(x[4].shape[0], -1) + x5 = x[5].view(x[5].shape[0], -1) + c0 = self.instance0(x0) + c1 = self.instance1(x1) + c2 = self.instance2(x2) + c3 = self.instance3(x3) + c4 = self.instance4(x4) + c5 = self.instance5(x5) + return (c0, c1, c2, c3, c4, c5), g_feature, h_feature + + +class NetWithLossCell(nn.Cell): + """Wrap loss function in network""" + def __init__(self, network): + super(NetWithLossCell, self).__init__() + self.network = network + self.loss_fn = nn.SoftmaxCrossEntropyWithLogits(sparse=True, reduction="mean") + + def construct(self, imgs, fids, pids, camids): + """Forward propagation""" + inputs, targets = imgs, pids + (c0, c1, c2, c3, c4, c5), _, _ = self.network(inputs) + loss0 = self.loss_fn(c0, targets) + loss1 = self.loss_fn(c1, targets) + loss2 = self.loss_fn(c2, targets) + loss3 = self.loss_fn(c3, targets) + loss4 = self.loss_fn(c4, targets) + loss5 = self.loss_fn(c5, targets) + loss = (loss0 + loss1 + loss2 + loss3 + loss4 + loss5) + return loss + +#for 310 infer +use_G_feature = config.use_G_feature +class PCB_infer(nn.Cell): + """PCB for inference with classifiers removed""" + def __init__(self): + super(PCB_infer, self).__init__() + self.part = 6 + resnet = resnet50(1000) + self.base = resnet + self.avgpool = ops.AvgPool(pad_mode="valid", kernel_size=(4, 8), strides=(4, 8)) + self.local_conv = nn.Conv2d(2048, 256, kernel_size=1, has_bias=False, \ +pad_mode="valid", weight_init=HeNormal(mode="fan_out")) + self.feat_bn2d = nn.BatchNorm2d(num_features=256) + self.relu = ops.ReLU() + self.expandDims = ops.ExpandDims() + self.norm = nn.Norm(axis=1) + + def construct(self, x): + """Forward propagation""" + x = self.base.conv1(x) + x = self.base.bn1(x) + x = self.base.relu(x) + x = self.base.pad(x) + x = self.base.maxpool(x) + x = self.base.layer1(x) + x = self.base.layer2(x) + x = self.base.layer3(x) + x = self.base.layer4(x) + x = self.avgpool(x) + g_feature = x / (self.expandDims(self.norm(x), 1)).expand_as(x) + x = self.local_conv(x) + h_feature = x / (self.expandDims(self.norm(x), 1)).expand_as(x) + if use_G_feature: + return g_feature + return h_feature diff --git a/research/cv/pcb/src/resnet.py b/research/cv/pcb/src/resnet.py new file mode 100644 index 0000000000000000000000000000000000000000..f52637339396ea5e5bbd1e351b9512b1cf7b5595 --- /dev/null +++ b/research/cv/pcb/src/resnet.py @@ -0,0 +1,302 @@ +# 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. +# ============================================================================ + +"""ResNet.""" +import math +import numpy as np +from scipy.stats import truncnorm +import mindspore.nn as nn +import mindspore.common.dtype as mstype +from mindspore.ops import operations as P +from mindspore.common.tensor import Tensor + + +def conv_variance_scaling_initializer(in_channel, out_channel, kernel_size): + fan_in = in_channel * kernel_size * kernel_size + scale = 1.0 + scale /= max(1., fan_in) + stddev = (scale ** 0.5) / .87962566103423978 + mu, sigma = 0, stddev + weight = truncnorm(-2, 2, loc=mu, scale=sigma).rvs(out_channel * in_channel * kernel_size * kernel_size) + weight = np.reshape(weight, (out_channel, in_channel, kernel_size, kernel_size)) + return Tensor(weight, dtype=mstype.float32) + + +def _weight_variable(shape, factor=0.01): + init_value = np.random.randn(*shape).astype(np.float32) * factor + return Tensor(init_value) + + +def calculate_gain(nonlinearity, param=None): + """calculate_gain""" + linear_fns = ['linear', 'conv1d', 'conv2d', 'conv3d', 'conv_transpose1d', 'conv_transpose2d', 'conv_transpose3d'] + res = 0 + if nonlinearity in linear_fns or nonlinearity == 'sigmoid': + res = 1 + elif nonlinearity == 'tanh': + res = 5.0 / 3 + elif nonlinearity == 'relu': + res = math.sqrt(2.0) + elif nonlinearity == 'leaky_relu': + if param is None: + negative_slope = 0.01 + elif not isinstance(param, bool) and isinstance(param, int) or isinstance(param, float): + negative_slope = param + else: + raise ValueError("negative_slope {} not a valid number".format(param)) + res = math.sqrt(2.0 / (1 + negative_slope ** 2)) + else: + raise ValueError("Unsupported nonlinearity {}".format(nonlinearity)) + return res + + +def _calculate_fan_in_and_fan_out(tensor): + """_calculate_fan_in_and_fan_out""" + dimensions = len(tensor) + if dimensions < 2: + raise ValueError("Fan in and fan out can not be computed for tensor with fewer than 2 dimensions") + if dimensions == 2: + fan_in = tensor[1] + fan_out = tensor[0] + else: + num_input_fmaps = tensor[1] + num_output_fmaps = tensor[0] + receptive_field_size = 1 + if dimensions > 2: + receptive_field_size = tensor[2] * tensor[3] + fan_in = num_input_fmaps * receptive_field_size + fan_out = num_output_fmaps * receptive_field_size + return fan_in, fan_out + + +def _calculate_correct_fan(tensor, mode): + mode = mode.lower() + valid_modes = ['fan_in', 'fan_out'] + if mode not in valid_modes: + raise ValueError("Mode {} not supported, please use one of {}".format(mode, valid_modes)) + fan_in, fan_out = _calculate_fan_in_and_fan_out(tensor) + return fan_in if mode == 'fan_in' else fan_out + + +def kaiming_normal(inputs_shape, a=0, mode='fan_in', nonlinearity='leaky_relu'): + fan = _calculate_correct_fan(inputs_shape, mode) + gain = calculate_gain(nonlinearity, a) + std = gain / math.sqrt(fan) + return np.random.normal(0, std, size=inputs_shape).astype(np.float32) + + +def kaiming_uniform(inputs_shape, a=0., mode='fan_in', nonlinearity='leaky_relu'): + fan = _calculate_correct_fan(inputs_shape, mode) + gain = calculate_gain(nonlinearity, a) + std = gain / math.sqrt(fan) + bound = math.sqrt(3.0) * std + return np.random.uniform(-bound, bound, size=inputs_shape).astype(np.float32) + +def _conv3x3(in_channel, out_channel, stride=1): + weight_shape = (out_channel, in_channel, 3, 3) + weight = Tensor(kaiming_normal(weight_shape, mode="fan_out", nonlinearity='relu')) + return nn.Conv2d(in_channel, out_channel, kernel_size=3, stride=stride, + padding=1, pad_mode='pad', weight_init=weight) + +def _conv1x1(in_channel, out_channel, stride=1): + weight_shape = (out_channel, in_channel, 1, 1) + weight = Tensor(kaiming_normal(weight_shape, mode="fan_out", nonlinearity='relu')) + return nn.Conv2d(in_channel, out_channel, kernel_size=1, stride=stride, + padding=0, pad_mode='pad', weight_init=weight) + +def _conv7x7(in_channel, out_channel, stride=1): + weight_shape = (out_channel, in_channel, 7, 7) + weight = Tensor(kaiming_normal(weight_shape, mode="fan_out", nonlinearity='relu')) + return nn.Conv2d(in_channel, out_channel, + kernel_size=7, stride=stride, padding=3, pad_mode='pad', weight_init=weight) + +def _bn(channel): + return nn.BatchNorm2d(channel, eps=1e-5, momentum=0.9, + gamma_init=1, beta_init=0, moving_mean_init=0, moving_var_init=1) + +def _fc(in_channel, out_channel): + weight_shape = (out_channel, in_channel) + weight = Tensor(kaiming_uniform(weight_shape, a=math.sqrt(5))) + return nn.Dense(in_channel, out_channel, has_bias=True, weight_init=weight, bias_init=0) + +class ResidualBlock(nn.Cell): + """ + ResNet V1 residual block definition. + + Args: + in_channel (int): Input channel. + out_channel (int): Output channel. + stride (int): Stride size for the first convolutional layer. Default: 1. + + Returns: + Tensor, output tensor. + + Examples: + >>> ResidualBlock(3, 256, stride=2) + """ + expansion = 4 + def __init__(self, + in_channel, + out_channel, + stride=1): + super(ResidualBlock, self).__init__() + self.stride = stride + channel = out_channel // self.expansion + self.conv1 = _conv1x1(in_channel, channel, stride=1) + self.bn1 = _bn(channel) + self.conv2 = _conv3x3(channel, channel, stride=stride) + self.bn2 = _bn(channel) + self.conv3 = _conv1x1(channel, out_channel, stride=1) + self.bn3 = _bn(out_channel) + self.relu = nn.ReLU() + self.down_sample = False + if stride != 1 or in_channel != out_channel: + self.down_sample = True + self.down_sample_layer = None + if self.down_sample: + self.down_sample_layer = nn.SequentialCell([_conv1x1(in_channel, out_channel, stride), _bn(out_channel)]) + + def construct(self, x): + """Forward propagation""" + identity = 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.down_sample: + identity = self.down_sample_layer(identity) + out = out + identity + out = self.relu(out) + return out + +class ResNet(nn.Cell): + """ + ResNet architecture. + + Args: + block (Cell): Block for network. + layer_nums (list): Numbers of block in different layers. + in_channels (list): Input channel in each layer. + out_channels (list): Output channel in each layer. + strides (list): Stride size in each layer. + num_classes (int): The number of classes that the training images are belonging to. + Returns: + Tensor, output tensor. + Examples: + >>> ResNet(ResidualBlock, + >>> [3, 4, 6, 3], + >>> [64, 256, 512, 1024], + >>> [256, 512, 1024, 2048], + >>> [1, 2, 2, 2], + >>> 10) + """ + + def __init__(self, + block, + layer_nums, + in_channels, + out_channels, + strides, + num_classes): + super(ResNet, self).__init__() + if not len(layer_nums) == len(in_channels) == len(out_channels) == 4: + raise ValueError("the length of layer_num, in_channels, out_channels list must be 4!") + self.conv1 = _conv7x7(3, 64, stride=2) + self.bn1 = _bn(64) + self.relu = nn.ReLU() + self.pad = nn.Pad(paddings=((0, 0), (0, 0), (1, 1), (1, 1))) + self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, pad_mode="valid") + self.layer1 = self._make_layer(block, + layer_nums[0], + in_channel=in_channels[0], + out_channel=out_channels[0], + stride=strides[0]) + self.layer2 = self._make_layer(block, + layer_nums[1], + in_channel=in_channels[1], + out_channel=out_channels[1], + stride=strides[1]) + self.layer3 = self._make_layer(block, + layer_nums[2], + in_channel=in_channels[2], + out_channel=out_channels[2], + stride=strides[2]) + self.layer4 = self._make_layer(block, + layer_nums[3], + in_channel=in_channels[3], + out_channel=out_channels[3], + stride=strides[3]) + self.mean = P.ReduceMean(keep_dims=True) + self.flatten = nn.Flatten() + self.end_point = _fc(out_channels[3], num_classes) + + def _make_layer(self, block, layer_num, in_channel, out_channel, stride): + """ + Make stage network of ResNet. + Args: + block (Cell): Resnet block. + layer_num (int): Layer number. + in_channel (int): Input channel. + out_channel (int): Output channel. + stride (int): Stride size for the first convolutional layer. + Returns: + SequentialCell, the output layer. + Examples: + >>> _make_layer(ResidualBlock, 3, 128, 256, 2) + """ + layers = [] + resnet_block = block(in_channel, out_channel, stride=stride) + layers.append(resnet_block) + for _ in range(1, layer_num): + resnet_block = block(out_channel, out_channel, stride=1) + layers.append(resnet_block) + return nn.SequentialCell(layers) + + def construct(self, x): + """Forward propagation""" + x = self.conv1(x) + x = self.bn1(x) + x = self.relu(x) + x = self.pad(x) + c1 = self.maxpool(x) + c2 = self.layer1(c1) + c3 = self.layer2(c2) + c4 = self.layer3(c3) + c5 = self.layer4(c4) + out = self.mean(c5, (2, 3)) + out = self.flatten(out) + out = self.end_point(out) + return out + +def resnet50(class_num=10): + """ + Get ResNet50 neural network. + Args: + class_num (int): Class number. + Returns: + Cell, cell instance of ResNet50 neural network. + Examples: + >>> net = resnet50(10) + """ + return ResNet(ResidualBlock, + [3, 4, 6, 3], + [64, 256, 512, 1024], + [256, 512, 1024, 2048], + [1, 2, 2, 1], #remove the final downsample: [1,2,2,2]-> [1,2,2,1] + class_num) diff --git a/research/cv/pcb/src/rpp.py b/research/cv/pcb/src/rpp.py new file mode 100644 index 0000000000000000000000000000000000000000..53150458808f1240b82ee96865ee0311f848a3c0 --- /dev/null +++ b/research/cv/pcb/src/rpp.py @@ -0,0 +1,180 @@ +# 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. +# ============================================================================ +"""rpp.py""" + +import mindspore.nn as nn +from mindspore.common.initializer import HeNormal, Normal, Constant + +import mindspore.ops as ops + +from src.model_utils.config import config +from src.resnet import resnet50 + +class RPP(nn.Cell): + """PCB+RPP""" + def __init__(self, num_classes): + super(RPP, self).__init__() + self.part = 6 + self.num_classes = num_classes + resnet = resnet50(1000) + self.base = resnet + self.dropout = nn.Dropout(keep_prob=0.5) + self.avg_pool3d = ops.AvgPool3D(kernel_size=(8, 1, 1), strides=(8, 1, 1), pad_mode="valid") + self.local_mask = nn.Conv2d(256, 6, kernel_size=1, pad_mode="valid", \ +has_bias=True, weight_init=HeNormal(mode="fan_out"), bias_init=Constant(0)) + self.local_conv = nn.Conv2d(2048, 256, kernel_size=1, has_bias=False, \ +pad_mode="valid", weight_init=HeNormal(mode="fan_out")) + self.feat_bn2d = nn.BatchNorm2d(num_features=256) + self.relu = ops.ReLU() + self.expandDims = ops.ExpandDims() + self.norm = nn.Norm(axis=1) + self.squeeze = ops.Squeeze(1) + self.avgpool2d = ops.AvgPool(kernel_size=(24, 8)) + self.softmax = ops.Softmax(axis=1) + self.split_1 = ops.Split(1, 6) + self.split_2 = ops.Split(2, 6) + self.concat = ops.Concat(2) + # define 6 classifiers + self.instance0 = nn.Dense(256, self.num_classes, weight_init=Normal(sigma=0.001), bias_init=Constant(0)) + self.instance1 = nn.Dense(256, self.num_classes, weight_init=Normal(sigma=0.001), bias_init=Constant(0)) + self.instance2 = nn.Dense(256, self.num_classes, weight_init=Normal(sigma=0.001), bias_init=Constant(0)) + self.instance3 = nn.Dense(256, self.num_classes, weight_init=Normal(sigma=0.001), bias_init=Constant(0)) + self.instance4 = nn.Dense(256, self.num_classes, weight_init=Normal(sigma=0.001), bias_init=Constant(0)) + self.instance5 = nn.Dense(256, self.num_classes, weight_init=Normal(sigma=0.001), bias_init=Constant(0)) + + def construct(self, x): + """Forward propagation""" + x = self.base.conv1(x) + x = self.base.bn1(x) + x = self.base.relu(x) + x = self.base.pad(x) + x = self.base.maxpool(x) + x = self.base.layer1(x) + x = self.base.layer2(x) + x = self.base.layer3(x) + x = self.base.layer4(x) + y = x + if self.training: + y = self.dropout(x) + y = self.expandDims(y, 1) + y = self.avg_pool3d(y) + y = self.squeeze(y) + center = self.avgpool2d(y) + y = y - center.expand_as(y) + local_mask = self.local_mask(y) + local_mask = self.softmax(local_mask) + lw = self.split_1(local_mask) + x = x * 6 + f0 = x * (lw[0].expand_as(x)) + f1 = x * (lw[1].expand_as(x)) + f2 = x * (lw[2].expand_as(x)) + f3 = x * (lw[3].expand_as(x)) + f4 = x * (lw[4].expand_as(x)) + f5 = x * (lw[5].expand_as(x)) + f0 = self.avgpool2d(f0) + f1 = self.avgpool2d(f1) + f2 = self.avgpool2d(f2) + f3 = self.avgpool2d(f3) + f4 = self.avgpool2d(f4) + f5 = self.avgpool2d(f5) + x = self.concat((f0, f1, f2, f3, f4, f5)) + feat = self.concat((f0, f1, f2, f3, f4, f5)) + g_feature = feat / (self.expandDims(self.norm(feat), 1)).expand_as(feat) + if self.training: + x = self.dropout(x) + x = self.local_conv(x) + h_feature = x / (self.expandDims(self.norm(x), 1)).expand_as(x) + x = self.feat_bn2d(x) + x = self.relu(x) + x = self.split_2(x) + x0 = x[0].view(x[0].shape[0], -1) + x1 = x[1].view(x[1].shape[0], -1) + x2 = x[2].view(x[2].shape[0], -1) + x3 = x[3].view(x[3].shape[0], -1) + x4 = x[4].view(x[4].shape[0], -1) + x5 = x[5].view(x[5].shape[0], -1) + c0 = self.instance0(x0) + c1 = self.instance1(x1) + c2 = self.instance2(x2) + c3 = self.instance3(x3) + c4 = self.instance4(x4) + c5 = self.instance5(x5) + return (c0, c1, c2, c3, c4, c5), g_feature, h_feature + +#for infer 310 +use_G_feature = config.use_G_feature +class RPP_infer(nn.Cell): + """PCB+RPP for inference""" + def __init__(self): + super(RPP_infer, self).__init__() + self.part = 6 + resnet = resnet50(1000) + self.base = resnet + self.avg_pool3d = ops.AvgPool3D(kernel_size=(8, 1, 1), strides=(8, 1, 1), pad_mode="valid") + self.local_mask = nn.Conv2d(256, 6, kernel_size=1, pad_mode="valid", \ +has_bias=True, weight_init=HeNormal(mode="fan_out"), bias_init=Constant(0)) + self.local_conv = nn.Conv2d(2048, 256, kernel_size=1, has_bias=False, \ +pad_mode="valid", weight_init=HeNormal(mode="fan_out")) + self.feat_bn2d = nn.BatchNorm2d(num_features=256) + self.relu = ops.ReLU() + self.expandDims = ops.ExpandDims() + self.norm = nn.Norm(axis=1) + self.squeeze = ops.Squeeze(1) + self.avgpool2d = ops.AvgPool(kernel_size=(24, 8)) + self.softmax = ops.Softmax(axis=1) + self.split_1 = ops.Split(1, 6) + self.concat = ops.Concat(2) + + def construct(self, x): + """Forward propagation""" + x = self.base.conv1(x) + x = self.base.bn1(x) + x = self.base.relu(x) + x = self.base.pad(x) + x = self.base.maxpool(x) + x = self.base.layer1(x) + x = self.base.layer2(x) + x = self.base.layer3(x) + x = self.base.layer4(x) + y = x + y = self.expandDims(y, 1) + y = self.avg_pool3d(y) + y = self.squeeze(y) + center = self.avgpool2d(y) + y = y - center.expand_as(y) + local_mask = self.local_mask(y) + local_mask = self.softmax(local_mask) + lw = self.split_1(local_mask) + x = x * 6 + f0 = x * (lw[0].expand_as(x)) + f1 = x * (lw[1].expand_as(x)) + f2 = x * (lw[2].expand_as(x)) + f3 = x * (lw[3].expand_as(x)) + f4 = x * (lw[4].expand_as(x)) + f5 = x * (lw[5].expand_as(x)) + f0 = self.avgpool2d(f0) + f1 = self.avgpool2d(f1) + f2 = self.avgpool2d(f2) + f3 = self.avgpool2d(f3) + f4 = self.avgpool2d(f4) + f5 = self.avgpool2d(f5) + x = self.concat((f0, f1, f2, f3, f4, f5)) + feat = self.concat((f0, f1, f2, f3, f4, f5)) + g_feature = feat / (self.expandDims(self.norm(feat), 1)).expand_as(feat) + x = self.local_conv(x) + h_feature = x / (self.expandDims(self.norm(x), 1)).expand_as(x) + if use_G_feature: + return g_feature + return h_feature diff --git a/research/cv/pcb/train.py b/research/cv/pcb/train.py new file mode 100644 index 0000000000000000000000000000000000000000..c63eb012a6fdd17c38f8cbf0221e553b15b77736 --- /dev/null +++ b/research/cv/pcb/train.py @@ -0,0 +1,162 @@ +# 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.py""" + +import sys +import os +import mindspore.nn as nn +from mindspore import context, set_seed +from mindspore.communication.management import init, get_rank +from mindspore import load_checkpoint, load_param_into_net +from mindspore.train.callback import CheckpointConfig, ModelCheckpoint, LossMonitor, TimeMonitor +from mindspore.train import Model +from mindspore.context import ParallelMode + +from src.model_utils.config import config +from src.dataset import create_dataset +from src.pcb import PCB, NetWithLossCell +from src.rpp import RPP +from src.eval_utils import apply_eval +from src.eval_callback import EvalCallBack +from src.logging import Logger +from src.lr_generator import get_lr +from src.model_utils.moxing_adapter import moxing_wrapper +from src.model_utils.device_adapter import get_rank_id, get_device_id + +set_seed(config.seed) + +def build_model(num_classes): + """Build model""" + model = None + if config.model_name == "PCB": + model = PCB(num_classes) + elif config.model_name == "RPP": + model = RPP(num_classes) + return model + +def init_group_params(model, train_batch_num): + """Init group params""" + group_params = None + backbone_params = model.base.trainable_params() + other_params = list(filter(lambda x: "base" not in x.name, model.trainable_params())) + lr_backbone = get_lr(lr_init=0, lr_max=config.learning_rate * config.lr_mult, \ +total_steps=train_batch_num * config.epoch_size, warmup_steps=train_batch_num * config.warmup_epoch_size, \ +decay_steps=train_batch_num * config.decay_epoch_size) + lr_other = get_lr(lr_init=0, lr_max=config.learning_rate, \ +total_steps=train_batch_num * config.epoch_size, warmup_steps=train_batch_num * config.warmup_epoch_size, \ +decay_steps=train_batch_num * config.decay_epoch_size) + group_params = [{"params": backbone_params, "lr": lr_backbone}, \ +{"params": other_params, "lr": lr_other}, \ +{'order_params': model.trainable_params()}] + return group_params + +def set_log_save_dir(): + """Set log save dir""" + log_save_dir = os.path.join(config.output_path, config.log_save_path) + if config.enable_modelarts and config.run_distribute: + log_save_dir = os.path.join(log_save_dir, 'train_log{}/'.format(get_rank_id())) + else: + if config.run_distribute: + log_save_dir = os.path.join(log_save_dir, 'train_log{}/'.format(get_rank())) + return log_save_dir + +def set_ckpt_save_dir(): + """Set checkpoint save dir""" + ckpt_save_dir = os.path.join(config.output_path, config.checkpoint_save_path) + if config.enable_modelarts and config.run_distribute: + ckpt_save_dir = os.path.join(ckpt_save_dir, 'ckpt_{}/'.format(get_rank_id())) + else: + if config.run_distribute: + ckpt_save_dir = os.path.join(ckpt_save_dir, 'ckpt_{}/'.format(get_rank())) + return ckpt_save_dir + +@moxing_wrapper() +def train_net(): + """train_net""" + target = config.device_target + # init context + if config.mode_name == 'GRAPH': + context.set_context(mode=context.GRAPH_MODE, device_target=target) + else: + context.set_context(mode=context.PYNATIVE_MODE, device_target=target, save_graphs=False) + if target == "Ascend": + device_id = get_device_id() + device_num = config.device_num + context.set_context(device_id=device_id) + if config.run_distribute: + context.reset_auto_parallel_context() + context.set_auto_parallel_context(device_num=device_num, \ +parallel_mode=ParallelMode.DATA_PARALLEL, gradients_mean=True) + init() + log_save_dir = set_log_save_dir() + if not os.path.isdir(log_save_dir): + os.makedirs(log_save_dir) + sys.stdout = Logger(os.path.join(log_save_dir, 'log.txt')) + #create dataset + train_dataset, train_set = create_dataset(dataset_name=config.dataset_name, \ +dataset_path=config.dataset_path, subset_name="train", batch_size=config.batch_size, \ +num_parallel_workers=config.num_parallel_workers, distribute=config.run_distribute) + train_batch_num = train_dataset.get_dataset_size() + num_classes = train_set.num_ids + #net + network = build_model(num_classes) + if config.checkpoint_file_path != "": + print("loading checkpoint from " + config.checkpoint_file_path) + param_dict = load_checkpoint(config.checkpoint_file_path) + load_param_into_net(network, param_dict) + #optimizer + loss_scale = float(config.loss_scale) + group_params = init_group_params(network, train_batch_num) + optimizer = nn.SGD(group_params, momentum=float(config.momentum), \ +weight_decay=float(config.weight_decay), nesterov=config.nesterov, loss_scale=loss_scale) + net = NetWithLossCell(network) + net = nn.TrainOneStepCell(net, optimizer, sens=loss_scale) + model = Model(net) + # define callbacks + time_cb = TimeMonitor(data_size=train_batch_num) + loss_cb = LossMonitor() + callbacks = [time_cb, loss_cb] + # checkpoint + if config.save_checkpoint: + ckpt_config = CheckpointConfig(save_checkpoint_steps=config.save_checkpoint_epochs * train_batch_num, \ +keep_checkpoint_max=config.keep_checkpoint_max) + ckpt_save_dir = set_ckpt_save_dir() + ckpoint_cb = ModelCheckpoint(prefix=config.model_name, directory=ckpt_save_dir, config=ckpt_config) + callbacks += [ckpoint_cb] + if config.save_checkpoint and config.run_eval: + eval_network = network + query_dataset, query_set = create_dataset(dataset_name=config.dataset_name, \ +dataset_path=config.dataset_path, subset_name="query", batch_size=config.batch_size, \ +num_parallel_workers=config.num_parallel_workers) + gallery_dataset, gallery_set = create_dataset(dataset_name=config.dataset_name, \ +dataset_path=config.dataset_path, subset_name="gallery", batch_size=config.batch_size, \ +num_parallel_workers=config.num_parallel_workers) + eval_param_dict = {"net": eval_network, "query_dataset": query_dataset, \ +"gallery_dataset": gallery_dataset, "query_set": query_set.data, "gallery_set": gallery_set.data} + eval_cb = EvalCallBack(apply_eval, eval_param_dict, interval=config.eval_interval, + eval_start_epoch=config.eval_start_epoch, save_best_ckpt=True, + ckpt_directory=ckpt_save_dir, best_ckpt_name="best.ckpt", + metrics_name=("mAP", "CMC"), cmc_topk=(1, 5, 10)) + callbacks += [eval_cb] + dataset_sink_mode = False + if config.sink_mode and config.device_target != "CPU": + print("In sink mode, one epoch return a loss.") + dataset_sink_mode = True + print("Start training {}, the first epoch will be slower because of the graph compilation.".format(\ +config.model_name)) + model.train(config.epoch_size, train_dataset, callbacks=callbacks, dataset_sink_mode=dataset_sink_mode) + +if __name__ == "__main__": + train_net()