Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SSD examples based on MindCV #704

Merged
merged 78 commits into from
Aug 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
3628a4b
add feature extraction for MobileNetV3, ConvNeXt, ResNeST, EfficientN…
DexterJZ May 5, 2023
c757f9a
adjust format
May 5, 2023
a28f579
adjust format again
May 5, 2023
0ff4e40
add PR#605 changes
DexterJZ May 12, 2023
47b8c9c
Merge branch 'mindspore-lab:main' into extract_feature
DexterJZ May 12, 2023
f97e89d
Merge branch 'mindspore-lab:main' into extract_feature
DexterJZ May 18, 2023
197a260
Merge branch 'mindspore-lab:main' into extract_feature
DexterJZ May 23, 2023
fe87414
Merge branch 'mindspore-lab:main' into extract_feature
DexterJZ May 23, 2023
61c7761
Merge branch 'mindspore-lab:main' into extract_feature
DexterJZ May 24, 2023
cd32049
Merge branch 'mindspore-lab:main' into extract_feature
DexterJZ May 30, 2023
af2d88d
feature extraction with nonsequential modules and ResNet building cha…
DexterJZ May 30, 2023
8b39222
HRNet supports feature extraction
DexterJZ May 31, 2023
8475bdd
feature extraction for ResNet, MobileNetV3, ConvNeXt, ResNeST, Effici…
DexterJZ Jun 1, 2023
dab7fdc
Merge branch 'extract_feature' of github.com:DexterJZ/mindcv into ext…
DexterJZ Jun 1, 2023
532c98e
fix linting issue
DexterJZ Jun 1, 2023
2473826
fix linting issue
DexterJZ Jun 1, 2023
ca70dd9
fix linting issue
DexterJZ Jun 1, 2023
9132901
fix linting issue
DexterJZ Jun 1, 2023
53c5e23
fix linting issue
DexterJZ Jun 1, 2023
6dad38e
discard doc changes
DexterJZ Jun 2, 2023
5ae1221
Merge branch 'mindspore-lab:main' into extract_feature
DexterJZ Jun 2, 2023
24552d1
Merge branch 'mindspore-lab:main' into extract_feature
DexterJZ Jun 4, 2023
02067ed
add ssd dataset and backbone
DexterJZ Jun 6, 2023
9a22de6
restore convnext
DexterJZ Jun 6, 2023
b2c1975
Merge branch 'mindspore-lab:main' into ssd
DexterJZ Jun 6, 2023
0576af6
fix convnext
DexterJZ Jun 6, 2023
3b54beb
Merge branch 'mindspore-lab:main' into ssd
DexterJZ Jun 8, 2023
a0e713f
finish ssd coding
DexterJZ Jun 8, 2023
0be0f02
Merge branch 'ssd' of github.com:DexterJZ/mindcv into ssd
DexterJZ Jun 8, 2023
87d373a
Merge branch 'mindspore-lab:main' into ssd
DexterJZ Jun 12, 2023
7c647c0
finish ssd implementation
DexterJZ Jun 12, 2023
6b06f7a
Merge branch 'mindspore-lab:main' into ssd
DexterJZ Jun 13, 2023
78a80e4
add ssh evaluation
DexterJZ Jun 13, 2023
2e482f2
Merge branch 'mindspore-lab:main' into ssd
DexterJZ Jun 14, 2023
09ca503
update amp_level setting
DexterJZ Jun 14, 2023
346f335
resolve conflicts
DexterJZ Jun 14, 2023
816659b
Merge branch 'ssd' of github.com:DexterJZ/mindcv into ssd
DexterJZ Jun 14, 2023
0c677de
fix format and mobilenet_v2
DexterJZ Jun 14, 2023
228a30e
resolve conflict
DexterJZ Jun 15, 2023
b608bc4
update ssd.yaml
DexterJZ Jun 15, 2023
3b0ac4d
Merge branch 'mindspore-lab:main' into ssd
DexterJZ Jun 19, 2023
c30e7f0
Merge branch 'mindspore-lab:main' into ssd
DexterJZ Jun 30, 2023
fec533d
finish ssd_resnet50_fpn
DexterJZ Jun 30, 2023
cf1a085
Update ssd_mobilenetv2.yaml
DexterJZ Jun 30, 2023
571aba7
Update ssd_resnet50_fpn.yaml
DexterJZ Jun 30, 2023
46fdae6
Update ssd_resnet50_fpn_gpu.yaml
DexterJZ Jun 30, 2023
edc5657
update ssd_eval
DexterJZ Jul 3, 2023
ebd4347
update ssd_model.py
DexterJZ Jul 4, 2023
e79293e
update configs
DexterJZ Jul 4, 2023
75222ef
Update ssd_resnet50_fpn_gpu.yaml
DexterJZ Jul 6, 2023
4d431ed
Update ssd_resnet50_fpn.yaml
DexterJZ Jul 6, 2023
1ea8c23
Update ssd_mobilenetv2.yaml
DexterJZ Jul 6, 2023
3255e42
Update ssd_mobilenetv2_gpu.yaml
DexterJZ Jul 6, 2023
f3fa2e7
Merge branch 'mindspore-lab:main' into ssd
DexterJZ Jul 6, 2023
4b3e957
rollback mobilenet_v2.py
DexterJZ Jul 13, 2023
efba500
rollback files
DexterJZ Jul 13, 2023
73988da
Merge branch 'mindspore-lab:main' into ssd
DexterJZ Jul 13, 2023
a16e7a9
reorganize code structure
DexterJZ Jul 13, 2023
e903449
Merge branch 'mindspore-lab:main' into ssd
DexterJZ Jul 20, 2023
0c3766b
refine ssd for mobilenetv2
DexterJZ Jul 20, 2023
19d2aa8
Merge branch 'mindspore-lab:main' into ssd
DexterJZ Jul 21, 2023
6ae22c1
Merge branch 'mindspore-lab:main' into ssd
DexterJZ Jul 21, 2023
84a2aa0
bug fix for ssd mobilenetv3
DexterJZ Jul 25, 2023
32e85f5
unify configs
DexterJZ Jul 25, 2023
4733fd1
Update ssd_resnet50_fpn.yaml
DexterJZ Jul 25, 2023
e6754b6
fix CI error
DexterJZ Jul 25, 2023
fa66bae
fix name mismatch between model param and ckpt param
DexterJZ Jul 26, 2023
2af9eb9
fix name mismatch between model param and ckpt param
DexterJZ Jul 26, 2023
ef1406b
Merge branch 'mindspore-lab:main' into ssd
DexterJZ Jul 26, 2023
af4e7a6
add readme.md for SSD
DexterJZ Jul 31, 2023
e3c684d
Merge branch 'ssd' of github.com:DexterJZ/mindcv into ssd
DexterJZ Jul 31, 2023
d3677b1
Merge branch 'mindspore-lab:main' into ssd
DexterJZ Aug 1, 2023
33e43da
finish README.md for SSD
DexterJZ Aug 1, 2023
ede13be
Update README.md
DexterJZ Aug 1, 2023
0dc3ff0
Update README.md
DexterJZ Aug 1, 2023
3e44efb
rename files
DexterJZ Aug 2, 2023
3ac589e
Update README.md
DexterJZ Aug 2, 2023
8d6918f
Merge branch 'mindspore-lab:main' into ssd
DexterJZ Aug 10, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
143 changes: 143 additions & 0 deletions examples/det/ssd/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
# SSD Based on MindCV Backbones

> [SSD: Single Shot MultiBox Detector](https://arxiv.org/abs/1512.02325)

## Introduction

SSD is an single-staged object detector. It discretizes the output space of bounding boxes into a set of default boxes over different aspect ratios and scales per feature map location, and combines predictions from multi-scale feature maps to detect objects with various sizes. At prediction time, SSD generates scores for the presence of each object category in each default box and produces adjustments to the box to better match the object shape.

<p align="center">
<img src="https://github.com/DexterJZ/mindcv/assets/16130861/50bc9627-c71c-4b1a-9de4-9e6040a43279" width=800 />
</p>
<p align="center">
<em>Figure 1. Architecture of SSD [<a href="#references">1</a>] </em>
</p>

In this example, by leveraging [the multi-scale feature extraction of MindCV](https://github.com/mindspore-lab/mindcv/blob/main/docs/en/how_to_guides/feature_extraction.md), we demonstrate that using backbones from MindCV much simplifies the implementation of SSD.

## Configurations

Here, we provide three configurations of SSD.
* Using [MobileNetV2](https://github.com/mindspore-lab/mindcv/tree/main/configs/mobilenetv2) as the backbone and the original detector described in the paper.
* Using [ResNet50](https://github.com/mindspore-lab/mindcv/tree/main/configs/resnet) as the backbone with a FPN and a shared-weight-based detector.
* Using [MobileNetV3](https://github.com/mindspore-lab/mindcv/tree/main/configs/mobilenetv3) as the backbone and the original detector described in the paper.

## Dataset

We train and test SSD using [COCO 2017 Dataset](https://cocodataset.org/#download). The dataset contains
* 118000 images about 18 GB for training, and
* 5000 images about 1 GB for testing.

## Quick Start

### Preparation

1. Clone MindCV repository by running
```
git clone https://github.com/mindspore-lab/mindcv.git
```

2. Install dependencies as shown [here](https://mindspore-lab.github.io/mindcv/installation/).

3. Download [COCO 2017 Dataset](https://cocodataset.org/#download), prepare the dataset as follows.
```
.
└─cocodataset
├─annotations
├─instance_train2017.json
└─instance_val2017.json
├─val2017
└─train2017
```
Run the following commands to preprocess the dataset and convert it to [MindRecord format](https://www.mindspore.cn/docs/zh-CN/master/api_python/mindspore.mindrecord.html) for reducing preprocessing time during training and testing.
```
cd mindcv # change directory to the root of MindCV repository
python examples/det/ssd/create_data.py coco --data_path [root of COCO 2017 Dataset] --out_path [directory for storing MindRecord files]
```
Specify the path of the preprocessed dataset at keyword `data_dir` in the config file.

4. Download the pretrained backbone weights from the table below, and specify the path to the backbone weights at keyword `backbone_ckpt_path` in the config file.
<div align="center">

| MobileNetV2 | ResNet50 | MobileNetV3 |
|:----------------:|:----------------:|:----------------:|
| [backbone weights](https://download.mindspore.cn/toolkits/mindcv/mobilenet/mobilenetv2/mobilenet_v2_100-d5532038.ckpt) | [backbone weights](https://download.mindspore.cn/toolkits/mindcv/resnet/resnet50-e0733ab8.ckpt) | [backbone weights](https://download.mindspore.cn/toolkits/mindcv/mobilenet/mobilenetv3/mobilenet_v3_large_100-1279ad5f.ckpt) |

</div>

### Train

It is highly recommended to use **distributed training** for this SSD implementation.

For distributed training using **OpenMPI's `mpirun`**, simply run
```
cd mindcv # change directory to the root of MindCV repository
mpirun -n [# of devices] python examples/det/ssd/train.py --config [the path to the config file]
```
For example, if train SSD distributively with the `MobileNetV2` configuration on 8 devices, run
```
cd mindcv # change directory to the root of MindCV repository
mpirun -n 8 python examples/det/ssd/train.py --config examples/det/ssd/ssd_mobilenetv2.yaml
```

For distributed training with [Ascend rank table](https://github.com/mindspore-lab/mindocr/blob/main/docs/en/tutorials/distribute_train.md#12-configure-rank_table_file-for-training), configure `ascend8p.sh` as follows
```
#!/bin/bash
export DEVICE_NUM=8
export RANK_SIZE=8
export RANK_TABLE_FILE="./hccl_8p_01234567_127.0.0.1.json"

for ((i = 0; i < ${DEVICE_NUM}; i++)); do
export DEVICE_ID=$i
export RANK_ID=$i
echo "Launching rank: ${RANK_ID}, device: ${DEVICE_ID}"
if [ $i -eq 0 ]; then
echo 'i am 0'
python examples/det/ssd/train.py --config [the path to the config file] &> ./train.log &
else
echo 'not 0'
python -u examples/det/ssd/train.py --config [the path to the config file] &> /dev/null &
fi
done
```
and start training by running
```
cd mindcv # change directory to the root of MindCV repository
bash ascend8p.sh
```

For single-device training, please run
```
cd mindcv # change directory to the root of MindCV repository
python examples/det/ssd/train.py --config [the path to the config file]
```

### Test

For testing the trained model, first specify the path to the model checkpoint at keyword `ckpt_path` in the config file, then run
```
cd mindcv # change directory to the root of MindCV repository
python examples/det/ssd/eval.py --config [the path to the config file]
```
For example, for testing SSD with the `MobileNetV2` configuration, run
```
cd mindcv # change directory to the root of MindCV repository
python examples/det/ssd/eval.py --config examples/det/ssd/ssd_mobilenetv2.yaml
```

## Performance

Here are the performance resutls and the pretrained model weights for each configuration.
<div align="center">

| Configuration | Mixed Precision | mAP | Config | Download |
|:-----------------:|:---------------:|:----:|:------:|:--------:|
| MobileNetV2 | O2 | 23.2 | [yaml](https://github.com/mindspore-lab/mindcv/blob/main/examples/det/ssd/ssd_mobilenetv2.yaml) | [weights](https://download.mindspore.cn/toolkits/mindcv/ssd/ssd_mobilenetv2-5bbd7411.ckpt) |
| ResNet50 with FPN | O3 | 38.3 | [yaml](https://github.com/mindspore-lab/mindcv/blob/main/examples/det/ssd/ssd_resnet50_fpn.yaml) | [weights](https://download.mindspore.cn/toolkits/mindcv/ssd/ssd_resnet50_fpn-ac87ddac.ckpt) |
| MobileNetV3 | O2 | 23.8 | [yaml](https://github.com/mindspore-lab/mindcv/blob/main/examples/det/ssd/ssd_mobilenetv3.yaml) | [weights](https://download.mindspore.cn/toolkits/mindcv/ssd/ssd_mobilenetv3-53d9f6e9.ckpt) |

</div>

## References

[1] Liu, W., Anguelov, D., Erhan, D., Szegedy, C., Reed, S., Fu, C. Y., & Berg, A. C. (2016). SSD: Single Shot Multibox Detector. In Computer Vision–ECCV 2016: 14th European Conference, Amsterdam, The Netherlands, October 11–14, 2016, Proceedings, Part I 14 (pp. 21-37). Springer International Publishing.
130 changes: 130 additions & 0 deletions examples/det/ssd/callbacks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import os
import stat

from utils import apply_eval

from mindspore import log as logger
from mindspore import save_checkpoint
from mindspore.train.callback import Callback, CheckpointConfig, LossMonitor, ModelCheckpoint, TimeMonitor


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.
best_ckpt_name (str): best checkpoint name, default is `best.ckpt`.
metrics_name (str): evaluation metrics name, default is `acc`.

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="acc",
):
super(EvalCallBack, self).__init__()
self.eval_function = eval_function
self.eval_param_dict = eval_param_dict
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_res = 0
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

def remove_ckpoint_file(self, file_name):
"""Remove the specified checkpoint file from this checkpoint manager and also from the directory."""
try:
os.chmod(file_name, stat.S_IWRITE)
os.remove(file_name)
except OSError:
logger.warning("OSError, failed to remove the older ckpt file %s.", file_name)
except ValueError:
logger.warning("ValueError, failed to remove the older ckpt file %s.", file_name)

def on_train_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:
res = self.eval_function(self.eval_param_dict)
print("epoch: {}, {}: {}".format(cur_epoch, self.metrics_name, res), flush=True)

if res >= self.best_res:
self.best_res = res
self.best_epoch = cur_epoch
print("update best result: {}".format(res), flush=True)

if self.save_best_ckpt:
if os.path.exists(self.best_ckpt_path):
self.remove_ckpoint_file(self.best_ckpt_path)

save_checkpoint(cb_params.train_network, self.best_ckpt_path)
print("update best checkpoint at: {}".format(self.best_ckpt_path), flush=True)

def on_train_end(self, run_context):
print(
"End training, the best {0} is: {1}, the best {0} epoch is {2}".format(
self.metrics_name, self.best_res, self.best_epoch
),
flush=True,
)


def get_ssd_callbacks(args, steps_per_epoch, rank_id):
ckpt_config = CheckpointConfig(keep_checkpoint_max=args.keep_checkpoint_max)
ckpt_cb = ModelCheckpoint(prefix="ssd", directory=args.ckpt_save_dir, config=ckpt_config)

if rank_id == 0:
return [TimeMonitor(data_size=steps_per_epoch), LossMonitor(), ckpt_cb]

return [TimeMonitor(data_size=steps_per_epoch), LossMonitor()]


def get_ssd_eval_callback(eval_net, eval_dataset, args):
if args.dataset == "coco":
anno_json = os.path.join(args.data_dir, "annotations/instances_val2017.json")
else:
raise NotImplementedError

eval_param_dict = {"net": eval_net, "dataset": eval_dataset, "anno_json": anno_json, "args": args}

eval_cb = EvalCallBack(
apply_eval,
eval_param_dict,
interval=args.eval_interval,
eval_start_epoch=args.eval_start_epoch,
save_best_ckpt=True,
ckpt_directory=args.ckpt_save_dir,
best_ckpt_name="best.ckpt",
metrics_name="mAP",
)

return eval_cb
Loading