sonebu
commited on
Commit
•
780c589
1
Parent(s):
3da970d
moving over from github
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .gitattributes +5 -0
- .gitignore +5 -0
- LICENSE +2 -0
- README.md +9 -3
- dataloader.py +513 -0
- efficientdet_comparison/coco_eval.py +301 -0
- efficientdet_comparison/hardware_experiment_best.pth.tar +3 -0
- efficientdet_comparison/readme.md +186 -0
- efficientdet_comparison/training_experiment_best.pth.tar +3 -0
- efficientdet_comparison/wider2coco.py +577 -0
- experiments/demo.gif +3 -0
- experiments/shallow800_mnv2ssdlite_8b_retrain_wider_optimizedAnchors_annealedlr_0_95/Histograms/histograms_fpt_cons_train_experiment/fpt_cons_train_bn_biaseses.jpg +3 -0
- experiments/shallow800_mnv2ssdlite_8b_retrain_wider_optimizedAnchors_annealedlr_0_95/Histograms/histograms_fpt_cons_train_experiment/fpt_cons_train_bn_weights.jpg +3 -0
- experiments/shallow800_mnv2ssdlite_8b_retrain_wider_optimizedAnchors_annealedlr_0_95/Histograms/histograms_fpt_cons_train_experiment/fpt_cons_train_layer_biaseses.jpg +3 -0
- experiments/shallow800_mnv2ssdlite_8b_retrain_wider_optimizedAnchors_annealedlr_0_95/Histograms/histograms_fpt_cons_train_experiment/fpt_cons_train_layer_weights.jpg +3 -0
- experiments/shallow800_mnv2ssdlite_8b_retrain_wider_optimizedAnchors_annealedlr_0_95/Histograms/histograms_original_experiment/original_bn_biaseses.jpg +3 -0
- experiments/shallow800_mnv2ssdlite_8b_retrain_wider_optimizedAnchors_annealedlr_0_95/Histograms/histograms_original_experiment/original_bn_weights.jpg +3 -0
- experiments/shallow800_mnv2ssdlite_8b_retrain_wider_optimizedAnchors_annealedlr_0_95/Histograms/histograms_original_experiment/original_layer_biaseses.jpg +3 -0
- experiments/shallow800_mnv2ssdlite_8b_retrain_wider_optimizedAnchors_annealedlr_0_95/Histograms/histograms_original_experiment/original_layer_weights.jpg +3 -0
- experiments/shallow800_mnv2ssdlite_8b_retrain_wider_optimizedAnchors_annealedlr_0_95/Histograms/histograms_qat_after_trained_experiment/qat_after_trained_bn_biaseses.jpg +3 -0
- experiments/shallow800_mnv2ssdlite_8b_retrain_wider_optimizedAnchors_annealedlr_0_95/Histograms/histograms_qat_after_trained_experiment/qat_after_trained_bn_weights.jpg +3 -0
- experiments/shallow800_mnv2ssdlite_8b_retrain_wider_optimizedAnchors_annealedlr_0_95/Histograms/histograms_qat_after_trained_experiment/qat_after_trained_layer_biaseses.jpg +3 -0
- experiments/shallow800_mnv2ssdlite_8b_retrain_wider_optimizedAnchors_annealedlr_0_95/Histograms/histograms_qat_after_trained_experiment/qat_after_trained_layer_weights.jpg +3 -0
- experiments/shallow800_mnv2ssdlite_8b_retrain_wider_optimizedAnchors_annealedlr_0_95/Histograms/histograms_qat_pre_trained_experiment/qat_pre_trained_bn_biaseses.jpg +3 -0
- experiments/shallow800_mnv2ssdlite_8b_retrain_wider_optimizedAnchors_annealedlr_0_95/Histograms/histograms_qat_pre_trained_experiment/qat_pre_trained_bn_weights.jpg +3 -0
- experiments/shallow800_mnv2ssdlite_8b_retrain_wider_optimizedAnchors_annealedlr_0_95/Histograms/histograms_qat_pre_trained_experiment/qat_pre_trained_layer_biaseses.jpg +3 -0
- experiments/shallow800_mnv2ssdlite_8b_retrain_wider_optimizedAnchors_annealedlr_0_95/Histograms/histograms_qat_pre_trained_experiment/qat_pre_trained_layer_weights.jpg +3 -0
- experiments/shallow800_mnv2ssdlite_8b_retrain_wider_optimizedAnchors_annealedlr_0_95/fpt_experiment.pth.tar +3 -0
- experiments/shallow800_mnv2ssdlite_8b_retrain_wider_optimizedAnchors_annealedlr_0_95/hardware_experiment.pth.tar +3 -0
- experiments/shallow800_mnv2ssdlite_8b_retrain_wider_optimizedAnchors_annealedlr_0_95/training_experiment.pth.tar +3 -0
- experiments/shallow830_mnv2ssdlite_2b8b_wider_somelayers_excluded_annealedlr_0_95/Histograms/histograms_fpt_cons_train_experiment/fpt_cons_train_bn_biaseses.jpg +3 -0
- experiments/shallow830_mnv2ssdlite_2b8b_wider_somelayers_excluded_annealedlr_0_95/Histograms/histograms_fpt_cons_train_experiment/fpt_cons_train_bn_weights.jpg +3 -0
- experiments/shallow830_mnv2ssdlite_2b8b_wider_somelayers_excluded_annealedlr_0_95/Histograms/histograms_fpt_cons_train_experiment/fpt_cons_train_layer_biaseses.jpg +3 -0
- experiments/shallow830_mnv2ssdlite_2b8b_wider_somelayers_excluded_annealedlr_0_95/Histograms/histograms_fpt_cons_train_experiment/fpt_cons_train_layer_weights.jpg +3 -0
- experiments/shallow830_mnv2ssdlite_2b8b_wider_somelayers_excluded_annealedlr_0_95/Histograms/histograms_original_experiment/original_bn_biaseses.jpg +3 -0
- experiments/shallow830_mnv2ssdlite_2b8b_wider_somelayers_excluded_annealedlr_0_95/Histograms/histograms_original_experiment/original_bn_weights.jpg +3 -0
- experiments/shallow830_mnv2ssdlite_2b8b_wider_somelayers_excluded_annealedlr_0_95/Histograms/histograms_original_experiment/original_layer_biaseses.jpg +3 -0
- experiments/shallow830_mnv2ssdlite_2b8b_wider_somelayers_excluded_annealedlr_0_95/Histograms/histograms_original_experiment/original_layer_weights.jpg +3 -0
- experiments/shallow830_mnv2ssdlite_2b8b_wider_somelayers_excluded_annealedlr_0_95/Histograms/histograms_qat_after_trained_experiment/qat_after_trained_bn_biaseses.jpg +3 -0
- experiments/shallow830_mnv2ssdlite_2b8b_wider_somelayers_excluded_annealedlr_0_95/Histograms/histograms_qat_after_trained_experiment/qat_after_trained_bn_weights.jpg +3 -0
- experiments/shallow830_mnv2ssdlite_2b8b_wider_somelayers_excluded_annealedlr_0_95/Histograms/histograms_qat_after_trained_experiment/qat_after_trained_layer_biaseses.jpg +3 -0
- experiments/shallow830_mnv2ssdlite_2b8b_wider_somelayers_excluded_annealedlr_0_95/Histograms/histograms_qat_after_trained_experiment/qat_after_trained_layer_weights.jpg +3 -0
- experiments/shallow830_mnv2ssdlite_2b8b_wider_somelayers_excluded_annealedlr_0_95/Histograms/histograms_qat_pre_trained_experiment/qat_pre_trained_bn_biaseses.jpg +3 -0
- experiments/shallow830_mnv2ssdlite_2b8b_wider_somelayers_excluded_annealedlr_0_95/Histograms/histograms_qat_pre_trained_experiment/qat_pre_trained_bn_weights.jpg +3 -0
- experiments/shallow830_mnv2ssdlite_2b8b_wider_somelayers_excluded_annealedlr_0_95/Histograms/histograms_qat_pre_trained_experiment/qat_pre_trained_layer_biaseses.jpg +3 -0
- experiments/shallow830_mnv2ssdlite_2b8b_wider_somelayers_excluded_annealedlr_0_95/Histograms/histograms_qat_pre_trained_experiment/qat_pre_trained_layer_weights.jpg +3 -0
- experiments/shallow830_mnv2ssdlite_2b8b_wider_somelayers_excluded_annealedlr_0_95/fpt_experiment.pth.tar +3 -0
- experiments/shallow830_mnv2ssdlite_2b8b_wider_somelayers_excluded_annealedlr_0_95/hardware_experiment.pth.tar +3 -0
- experiments/shallow830_mnv2ssdlite_2b8b_wider_somelayers_excluded_annealedlr_0_95/modified_model.py +147 -0
- experiments/shallow830_mnv2ssdlite_2b8b_wider_somelayers_excluded_annealedlr_0_95/training_experiment.pth.tar +3 -0
.gitattributes
CHANGED
@@ -33,3 +33,8 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
36 |
+
*.pth.tar filter=lfs diff=lfs merge=lfs -text
|
37 |
+
*.json filter=lfs diff=lfs merge=lfs -text
|
38 |
+
*.gif filter=lfs diff=lfs merge=lfs -text
|
39 |
+
*.jpg filter=lfs diff=lfs merge=lfs -text
|
40 |
+
*.png filter=lfs diff=lfs merge=lfs -text
|
.gitignore
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
**/__pycache__/
|
2 |
+
**/.ipynb_checkpoints/
|
3 |
+
**/data/
|
4 |
+
**/datasets/
|
5 |
+
**/development/
|
LICENSE
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
Demo software - Experiments on person tracking with quantized networks by HyperbeeAI
|
2 |
+
Copyrights © 2023 Hyperbee.AI Inc. All rights reserved. main@shallow.ai
|
README.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1 |
-
|
2 |
-
|
3 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Experiments on person tracking with quantized networks by HyperbeeAI
|
2 |
+
|
3 |
+
Copyrights © 2023 Hyperbee.AI Inc. All rights reserved. main@shallow.ai
|
4 |
+
|
5 |
+
This repository contains our experiments for quantized neural networks for the person tracking task, evaluated over the WIDER pedestrian surveillance dataset.
|
6 |
+
|
7 |
+
See efficientdet_comparison/ for the comparison of our trained models with efficientdet
|
8 |
+
|
9 |
+
![demo](./experiments/demo.gif)
|
dataloader.py
ADDED
@@ -0,0 +1,513 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
###########################################################################
|
2 |
+
# Computer vision - Embedded person tracking demo software by HyperbeeAI. #
|
3 |
+
# Copyrights © 2023 Hyperbee.AI Inc. All rights reserved. main@shallow.ai #
|
4 |
+
###########################################################################
|
5 |
+
import os, sys, random, torch, torchvision
|
6 |
+
from torchvision import transforms
|
7 |
+
from torchvision.datasets.vision import VisionDataset
|
8 |
+
import torchvision.ops as ops
|
9 |
+
import torch.utils.data
|
10 |
+
import numpy as np
|
11 |
+
import pandas as pd
|
12 |
+
import copy
|
13 |
+
from PIL import Image
|
14 |
+
import os.path
|
15 |
+
import time, json
|
16 |
+
from typing import Any, Callable, Optional, Tuple, List
|
17 |
+
from typing import Callable
|
18 |
+
|
19 |
+
|
20 |
+
class input_fxpt_normalize:
|
21 |
+
def __init__(self, act_8b_mode):
|
22 |
+
self.act_8b_mode = act_8b_mode
|
23 |
+
|
24 |
+
def __call__(self, img):
|
25 |
+
if(self.act_8b_mode):
|
26 |
+
return img.sub(0.5).mul(256.).round().clamp(min=-128, max=127)
|
27 |
+
return img.sub(0.5).mul(256.).round().clamp(min=-128, max=127).div(128.)
|
28 |
+
|
29 |
+
|
30 |
+
### Emre Can: Our COCO Dataloder for training classes at specific ratio in every batch.
|
31 |
+
def class_lookup(cls):
|
32 |
+
c = list(cls.__bases__)
|
33 |
+
for base in c:
|
34 |
+
c.extend(class_lookup(base))
|
35 |
+
return c
|
36 |
+
|
37 |
+
# ref: https://pytorch.org/vision/main/_modules/torchvision/datasets/coco.html
|
38 |
+
class CocoDetection(VisionDataset):
|
39 |
+
"""`MS Coco Detection <https://cocodataset.org/#detection-2016>`_ Dataset.
|
40 |
+
Args:
|
41 |
+
root (string): Root directory where images are downloaded to.
|
42 |
+
|
43 |
+
annFile (string): Path to json annotation file.
|
44 |
+
|
45 |
+
scaleImgforCrop (int, optional): Img and target BBs are scaled with
|
46 |
+
constant aspect ratio st:
|
47 |
+
if image width, image height > scaleImgforCrop image is shrinked
|
48 |
+
until width or height becomes equal to scaleImgforCrop
|
49 |
+
|
50 |
+
if image width, image height < scaleImgforCrop image is expanded
|
51 |
+
until width or height becomes equal to scaleImgforCrop
|
52 |
+
|
53 |
+
else no scaling
|
54 |
+
fit_full_img: If it is set to true, image is scaled t fully fit in the window specified by "scaleImgforCrop x scaleImgforCrop"
|
55 |
+
transform (callable, optional): A function/transform that takes in an
|
56 |
+
PIL image and returns a transformed version. E.g, ``transforms.ToTensor``
|
57 |
+
|
58 |
+
target_transform (callable, optional): A function/transform that takes in
|
59 |
+
the target and transforms it.
|
60 |
+
transforms (callable, optional): A function/transform that takes input
|
61 |
+
sample and its target as entry and returns a transformed version.
|
62 |
+
"""
|
63 |
+
|
64 |
+
def __init__(
|
65 |
+
self,
|
66 |
+
root: str,
|
67 |
+
annFile: str,
|
68 |
+
scaleImgforCrop: int= None,
|
69 |
+
fit_full_img = False,
|
70 |
+
transform: Optional[Callable] = None,
|
71 |
+
target_transform: Optional[Callable] = None,
|
72 |
+
transforms: Optional[Callable] = None
|
73 |
+
):
|
74 |
+
super().__init__(root, transforms, transform, target_transform)
|
75 |
+
from pycocotools.coco import COCO
|
76 |
+
|
77 |
+
self.coco = COCO(annFile)
|
78 |
+
self.ids = list(sorted(self.coco.imgs.keys()))
|
79 |
+
self.annFilePath = os.path.join('.',annFile)
|
80 |
+
self.catPersonId = self.coco.getCatIds(catNms=['person'])[0]
|
81 |
+
self.scaleImgforCrop = scaleImgforCrop
|
82 |
+
self.fit_full_img = fit_full_img
|
83 |
+
|
84 |
+
|
85 |
+
def _load_image(self, id: int) -> Image.Image:
|
86 |
+
path = self.coco.loadImgs(id)[0]["file_name"]
|
87 |
+
return Image.open(os.path.join(self.root, path)).convert("RGB")
|
88 |
+
|
89 |
+
def _load_target(self, id) -> List[Any]:
|
90 |
+
return self.coco.loadAnns(self.coco.getAnnIds(id, iscrowd=False))
|
91 |
+
|
92 |
+
def __getitem__(self, index: int) -> Tuple[Any, Any, Any]:
|
93 |
+
|
94 |
+
id = self.ids[index]
|
95 |
+
imgID = id
|
96 |
+
|
97 |
+
try:
|
98 |
+
image = self._load_image(id)
|
99 |
+
except:
|
100 |
+
print(f'********Unable to load image with id: {imgID}********')
|
101 |
+
print('Please check if image is corrupted, and remove it from annotations if necessary.')
|
102 |
+
|
103 |
+
|
104 |
+
target = copy.deepcopy(self._load_target(id)) # deepcopy target list beforecentercrop manip, to be abe to work with same
|
105 |
+
# dateset without reloading it
|
106 |
+
|
107 |
+
image_width = image.size[0]
|
108 |
+
image_height = image.size[1]
|
109 |
+
|
110 |
+
|
111 |
+
# If necesary rescale the image and BBs near the size of planned center crop as much as possible
|
112 |
+
scale = self._calcPrescale(image_width=image_width, image_height=image_height)
|
113 |
+
image = self._prescaleImage(image, scale)
|
114 |
+
|
115 |
+
for i, t in enumerate(target):
|
116 |
+
BB = t['bbox'].copy()
|
117 |
+
scaledBB = self._prescaleBB(BB,scale)
|
118 |
+
target[i]['bbox'] = scaledBB
|
119 |
+
|
120 |
+
|
121 |
+
|
122 |
+
# Image width height after prescaling
|
123 |
+
image_width = image.size[0]
|
124 |
+
image_height = image.size[1]
|
125 |
+
|
126 |
+
# Check if center crop applied
|
127 |
+
centerCropped = False
|
128 |
+
if self.transforms is not None:
|
129 |
+
image, target = self.transforms(image, target)
|
130 |
+
|
131 |
+
# If center crop applied, transform BBs as well
|
132 |
+
for t in self.transforms.transform.transforms:
|
133 |
+
if (type(t) == torchvision.transforms.transforms.CenterCrop):
|
134 |
+
centerCropped = True
|
135 |
+
|
136 |
+
|
137 |
+
|
138 |
+
x_scale = image.size(2) / image_width
|
139 |
+
y_scale = image.size(1) / image_height
|
140 |
+
|
141 |
+
bbox_arr = []
|
142 |
+
|
143 |
+
for idx,ann in enumerate(target):
|
144 |
+
if ann['category_id'] == self.catPersonId:
|
145 |
+
crop_size = image.shape[1]
|
146 |
+
|
147 |
+
if centerCropped:
|
148 |
+
bbox = ann['bbox'].copy()
|
149 |
+
croppedBB = self.cropBBox(bbox, crop_size,image_height,image_width)
|
150 |
+
else:
|
151 |
+
croppedBB = torch.tensor(ann['bbox'])
|
152 |
+
|
153 |
+
if not (croppedBB == None):
|
154 |
+
bbox_arr.append(croppedBB)
|
155 |
+
|
156 |
+
if len(bbox_arr) != 0:
|
157 |
+
bbox_arr = torch.stack(bbox_arr)
|
158 |
+
wh = bbox_arr[:, 2:]
|
159 |
+
xy = bbox_arr[:, :2]
|
160 |
+
|
161 |
+
id_tensor = torch.tensor([id]).unsqueeze(0).expand(bbox_arr.size(0), -1)
|
162 |
+
|
163 |
+
bbox_arr = torch.cat([id_tensor, xy, wh], dim=-1)
|
164 |
+
else:
|
165 |
+
bbox_arr = torch.tensor(bbox_arr)
|
166 |
+
|
167 |
+
return image, bbox_arr , imgID
|
168 |
+
|
169 |
+
def __len__(self) -> int:
|
170 |
+
return len(self.ids)
|
171 |
+
|
172 |
+
def get_labels(self):
|
173 |
+
labels = []
|
174 |
+
for id in self.ids:
|
175 |
+
anns = self._load_target(id)
|
176 |
+
person_flag = False
|
177 |
+
for ann in anns:
|
178 |
+
person_flag = ann['category_id'] == self.catPersonId
|
179 |
+
if person_flag == True:
|
180 |
+
break
|
181 |
+
if person_flag == True:
|
182 |
+
labels.append(1)
|
183 |
+
else:
|
184 |
+
labels.append(0)
|
185 |
+
return torch.tensor(labels)
|
186 |
+
|
187 |
+
def get_cat_person_id(self):
|
188 |
+
return self.catPersonId
|
189 |
+
|
190 |
+
def get_coco_api(self):
|
191 |
+
return self.coco
|
192 |
+
|
193 |
+
|
194 |
+
# Functions defined for prescaling images/targets before center crop operation
|
195 |
+
def _calcPrescale(self, image_width, image_height):
|
196 |
+
# Calculate scale factor to shrink/expand image to coincide width or height to croppig area
|
197 |
+
scale = 1.0
|
198 |
+
if self.scaleImgforCrop != None:
|
199 |
+
if self.fit_full_img:
|
200 |
+
max_size = max(image_width, image_height)
|
201 |
+
scale = max_size/self.scaleImgforCrop
|
202 |
+
else:
|
203 |
+
# image fully encapsulates cropping area or vice versa
|
204 |
+
if ((image_width-self.scaleImgforCrop)*(image_height-self.scaleImgforCrop) > 0):
|
205 |
+
# if width of original image is closer to crop area
|
206 |
+
if abs(1-image_width/self.scaleImgforCrop) < abs(1-image_height/self.scaleImgforCrop):
|
207 |
+
scale = image_width/self.scaleImgforCrop
|
208 |
+
else:
|
209 |
+
scale = image_height/self.scaleImgforCrop
|
210 |
+
return scale
|
211 |
+
|
212 |
+
# Scales the image with defined scale
|
213 |
+
def _prescaleImage(self, image, scale):
|
214 |
+
image_width = int(image.size[0]/scale)
|
215 |
+
image_height = int(image.size[1]/scale)
|
216 |
+
|
217 |
+
t = transforms.Resize([image_height,image_width])
|
218 |
+
image = t(image)
|
219 |
+
return image
|
220 |
+
|
221 |
+
# Scales the targets with defined scale
|
222 |
+
def _prescaleBB(self, BB, scale):
|
223 |
+
scaledbb = [round(p/scale,1) for p in BB]
|
224 |
+
return scaledbb
|
225 |
+
|
226 |
+
|
227 |
+
def cropBBox(self,bbox,crop_size, image_height, image_width):
|
228 |
+
|
229 |
+
bbox_aligned = []
|
230 |
+
x, y, w, h = bbox[0], bbox[1], bbox[2], bbox[3]
|
231 |
+
|
232 |
+
# Casses for cropping
|
233 |
+
if image_height < crop_size:
|
234 |
+
offset = (crop_size - image_height) // 2
|
235 |
+
y = y + offset
|
236 |
+
if (y+h) > crop_size:
|
237 |
+
offset = (y+h)-crop_size
|
238 |
+
h = h - offset
|
239 |
+
if image_width < crop_size:
|
240 |
+
offset = (crop_size - image_width) // 2
|
241 |
+
x = x + offset
|
242 |
+
if (x+w) > crop_size:
|
243 |
+
offset = (x+w)-crop_size
|
244 |
+
w = w - offset
|
245 |
+
if image_width > crop_size:
|
246 |
+
offset = (image_width - crop_size) // 2
|
247 |
+
if offset > x:
|
248 |
+
# Deal with BB coincide with left cropping boundary
|
249 |
+
w = w -(offset-x)
|
250 |
+
x = 0
|
251 |
+
else:
|
252 |
+
x = x - offset
|
253 |
+
|
254 |
+
# Deal with BB coincide with right cropping boundary
|
255 |
+
if (x+w) > crop_size:
|
256 |
+
offset = (x+w)-crop_size
|
257 |
+
w = w - offset
|
258 |
+
|
259 |
+
if image_height > crop_size:
|
260 |
+
|
261 |
+
offset = (image_height - crop_size) // 2
|
262 |
+
if offset > y:
|
263 |
+
# Deal with BB coincide with top cropping boundary
|
264 |
+
h = h -(offset-y)
|
265 |
+
y = 0
|
266 |
+
else:
|
267 |
+
y = y - offset
|
268 |
+
# Deal with BB coincide with bottom cropping boundary
|
269 |
+
if (y+h) > crop_size:
|
270 |
+
offset = (y+h)-crop_size
|
271 |
+
h = h - offset
|
272 |
+
|
273 |
+
bbox_aligned.append(x)
|
274 |
+
bbox_aligned.append(y)
|
275 |
+
bbox_aligned.append(w)
|
276 |
+
bbox_aligned.append(h)
|
277 |
+
|
278 |
+
if ((w <= 0) or (h <= 0)):
|
279 |
+
return None
|
280 |
+
else:
|
281 |
+
x_scale, y_scale = 1.0,1.0
|
282 |
+
return torch.mul(torch.tensor(bbox_aligned), torch.tensor([x_scale, y_scale, x_scale, y_scale]))
|
283 |
+
|
284 |
+
def __round_floats(self,o):
|
285 |
+
'''
|
286 |
+
Used to round floats before writing to json file
|
287 |
+
'''
|
288 |
+
if isinstance(o, float):
|
289 |
+
return round(o, 2)
|
290 |
+
if isinstance(o, dict):
|
291 |
+
return {k: self.__round_floats(v) for k, v in o.items()}
|
292 |
+
if isinstance(o, (list, tuple)):
|
293 |
+
return [self.__round_floats(x) for x in o]
|
294 |
+
return o
|
295 |
+
|
296 |
+
def _check_if_annot_ignored(self, annot_bbox, ignore_bboxes):
|
297 |
+
'''gets an annotation and ignore bboxes list in [xmin, ymin, w, h] form and calculates the percentage
|
298 |
+
of the overlapping area. If overlapping area exceeds 50% for any ignore part, returns True, otherwise returns False
|
299 |
+
'''
|
300 |
+
annot_bbox = annot_bbox.copy()
|
301 |
+
annot_area = max(annot_bbox[2] * annot_bbox[3], 0)
|
302 |
+
annot_bbox[2] = annot_bbox[0] + annot_bbox[2]
|
303 |
+
annot_bbox[3] = annot_bbox[1] + annot_bbox[3]
|
304 |
+
|
305 |
+
for ignore_bbox in ignore_bboxes:
|
306 |
+
|
307 |
+
ignore_bbox = ignore_bbox.copy()
|
308 |
+
|
309 |
+
ignore_bbox[2] = ignore_bbox[0] + ignore_bbox[2]
|
310 |
+
ignore_bbox[3] = ignore_bbox[1] + ignore_bbox[3]
|
311 |
+
|
312 |
+
x_min_intersect = max(annot_bbox[0], ignore_bbox[0])
|
313 |
+
y_min_intersect = max(annot_bbox[1], ignore_bbox[1])
|
314 |
+
x_max_intersect = min(annot_bbox[2], ignore_bbox[2])
|
315 |
+
y_max_intersect = min(annot_bbox[3], ignore_bbox[3])
|
316 |
+
w = max(x_max_intersect - x_min_intersect, 0)
|
317 |
+
h = max(y_max_intersect - y_min_intersect, 0)
|
318 |
+
|
319 |
+
if annot_area <= 0:
|
320 |
+
return True
|
321 |
+
|
322 |
+
if w * h / annot_area > 0.5:
|
323 |
+
return True
|
324 |
+
|
325 |
+
return False
|
326 |
+
|
327 |
+
|
328 |
+
def createResizedAnnotJson(self,targetFileName,cropsize=512, mask_ignore_parts=False, ignore_parts_file=None):
|
329 |
+
'''
|
330 |
+
Resizes person annotations after center crop operation and saves as json file to the
|
331 |
+
directory of original annotations with the name "targetFileName"
|
332 |
+
|
333 |
+
If 'mask_ignore_parts' flag set to true and corresponding wider dataset ignore_parts_file supplied,
|
334 |
+
annotations having 50% or more overlap with an ignore part are deleted.
|
335 |
+
|
336 |
+
'''
|
337 |
+
|
338 |
+
# Get ignore part bb's in to a dictionary, wit image names as keys
|
339 |
+
if mask_ignore_parts:
|
340 |
+
ignore_part_dict = {}
|
341 |
+
with open(ignore_parts_file) as f:
|
342 |
+
for t, ignore_raw in enumerate(f):
|
343 |
+
ignore_raw = ignore_raw.split()
|
344 |
+
imgName = ignore_raw[:1][0]
|
345 |
+
|
346 |
+
BBs_str = ignore_raw[1:]
|
347 |
+
bb_raw = [int(bb) for bb in BBs_str]
|
348 |
+
|
349 |
+
BBs = []
|
350 |
+
bb = []
|
351 |
+
for i, p in enumerate(bb_raw):
|
352 |
+
bb.append(p)
|
353 |
+
if ((i+1)%4 == 0):
|
354 |
+
|
355 |
+
BBs.append(bb)
|
356 |
+
bb = []
|
357 |
+
|
358 |
+
ignore_part_dict[imgName] = BBs
|
359 |
+
|
360 |
+
|
361 |
+
t1 = time.time()
|
362 |
+
# Get original json annot file path, and create pah for resized json annot file
|
363 |
+
path, annotfilename = os.path.split(self.annFilePath)
|
364 |
+
resizedAnnotPath = os.path.join(path,targetFileName)
|
365 |
+
|
366 |
+
print('')
|
367 |
+
print(f'Creating Json file for resized annotations: {resizedAnnotPath}')
|
368 |
+
|
369 |
+
|
370 |
+
# Load original annotation json file as dictionary and assign it to resized annot dict
|
371 |
+
with open(self.annFilePath) as json_file:
|
372 |
+
resizedanotDict = json.load(json_file)
|
373 |
+
|
374 |
+
# Original annotations array
|
375 |
+
origannList = resizedanotDict['annotations']
|
376 |
+
|
377 |
+
# Check if center crop applied
|
378 |
+
centerCropped = False
|
379 |
+
if self.transforms is not None:
|
380 |
+
# If center crop applied, transform BBs as well
|
381 |
+
for t in self.transforms.transform.transforms:
|
382 |
+
if (type(t) == torchvision.transforms.transforms.CenterCrop):
|
383 |
+
centerCropped = True
|
384 |
+
|
385 |
+
|
386 |
+
resizedannList = []
|
387 |
+
for resizedannot in origannList:
|
388 |
+
|
389 |
+
currentcatID = resizedannot['category_id']
|
390 |
+
currentBB = resizedannot['bbox']
|
391 |
+
currentImgID = resizedannot['image_id']
|
392 |
+
|
393 |
+
# if annotations overlaps with an ignore part, do not add it to new annot file
|
394 |
+
if mask_ignore_parts:
|
395 |
+
image_name = self.coco.loadImgs(currentImgID)[0]['file_name']
|
396 |
+
if image_name in ignore_part_dict:
|
397 |
+
ignoreBBs = ignore_part_dict[image_name]
|
398 |
+
is_ignored = False
|
399 |
+
is_ignored = self._check_if_annot_ignored(resizedannot['bbox'].copy(), ignoreBBs)
|
400 |
+
|
401 |
+
if is_ignored:
|
402 |
+
continue
|
403 |
+
|
404 |
+
# Get crop size and original image sizes
|
405 |
+
image_width = self.coco.loadImgs(currentImgID)[0]['width']
|
406 |
+
image_height = self.coco.loadImgs(currentImgID)[0]['height']
|
407 |
+
|
408 |
+
|
409 |
+
# If presclae applied to image, calculate new image width and height
|
410 |
+
scale = self._calcPrescale(image_width=image_width, image_height=image_height)
|
411 |
+
image_width = image_width / scale
|
412 |
+
image_height = image_height / scale
|
413 |
+
|
414 |
+
if currentcatID == self.catPersonId:
|
415 |
+
# if BB is person
|
416 |
+
bbox = resizedannot['bbox'].copy()
|
417 |
+
|
418 |
+
# If prescale appied to image, resize annotations BBs
|
419 |
+
bbox = self._prescaleBB(bbox, scale)
|
420 |
+
|
421 |
+
# If center crop applied, crop/recalculate BBs as well
|
422 |
+
if centerCropped:
|
423 |
+
croppedBB = self.cropBBox(bbox, cropsize,image_height,image_width)
|
424 |
+
else:
|
425 |
+
croppedBB = torch.tensor(bbox)
|
426 |
+
|
427 |
+
if (croppedBB != None):
|
428 |
+
# If BB is person and valid after crop, add it to resized annotations list
|
429 |
+
croppedBB = croppedBB.tolist()
|
430 |
+
resizedannot['bbox'] = self.__round_floats(croppedBB)
|
431 |
+
resizedannot['area'] = self.__round_floats(croppedBB[2]*croppedBB[3])
|
432 |
+
resizedannList.append(resizedannot)
|
433 |
+
else:
|
434 |
+
# If BB is non-person add it to resized annotations list as it is
|
435 |
+
resizedannList.append(resizedannot)
|
436 |
+
|
437 |
+
# If prescale or center-crop applied
|
438 |
+
# Change width and height information of "images" field in annotations file
|
439 |
+
origImgList = resizedanotDict['images']
|
440 |
+
|
441 |
+
for i, imagInfo in enumerate(origImgList):
|
442 |
+
curInfo = origImgList[i]
|
443 |
+
image_width = curInfo['width']
|
444 |
+
image_height = curInfo['height']
|
445 |
+
|
446 |
+
if centerCropped:
|
447 |
+
curInfo['width'] = cropsize
|
448 |
+
curInfo['height'] = cropsize
|
449 |
+
else:
|
450 |
+
scale = self._calcPrescale(image_width=image_width, image_height=image_height)
|
451 |
+
curInfo['width'] = int(image_width / scale)
|
452 |
+
curInfo['height'] = int(image_height / scale)
|
453 |
+
|
454 |
+
origImgList[i] = curInfo.copy()
|
455 |
+
|
456 |
+
resizedanotDict['images'] = origImgList
|
457 |
+
resizedanotDict['annotations'] = resizedannList
|
458 |
+
print('Saving resized annotations to json file...')
|
459 |
+
|
460 |
+
# Save resized annotations in json file
|
461 |
+
resizedanotDict = json.dumps(resizedanotDict)
|
462 |
+
with open(resizedAnnotPath, 'w') as outfile:
|
463 |
+
outfile.write(resizedanotDict)
|
464 |
+
|
465 |
+
print(f'{resizedAnnotPath} saved.')
|
466 |
+
t2 = time.time()
|
467 |
+
print(f'Elapsed time: {t2-t1} seconds')
|
468 |
+
|
469 |
+
# ref: https://github.com/ufoym/imbalanced-dataset-sampler
|
470 |
+
class ImbalancedDatasetSampler(torch.utils.data.sampler.Sampler):
|
471 |
+
"""Samples elements randomly from a given list of indices for imbalanced dataset
|
472 |
+
Arguments:
|
473 |
+
indices: a list of indices
|
474 |
+
num_samples: number of samples to draw
|
475 |
+
constantSeed: Make it true if you want same random at each run
|
476 |
+
callback_get_label: a callback-like function which takes two arguments - dataset and index
|
477 |
+
"""
|
478 |
+
|
479 |
+
def __init__(self, dataset,constantSeed: bool = False, indices: list = None, num_samples: int = None,
|
480 |
+
callback_get_label: Callable = None, ratio: int = 4):
|
481 |
+
# if indices is not provided, all elements in the dataset will be considered
|
482 |
+
self.constantSeed = constantSeed
|
483 |
+
self.indices = list(range(len(dataset))) if indices is None else indices
|
484 |
+
|
485 |
+
# define custom callback
|
486 |
+
self.callback_get_label = callback_get_label
|
487 |
+
|
488 |
+
# if num_samples is not provided, draw `len(indices)` samples in each iteration
|
489 |
+
self.num_samples = len(self.indices) if num_samples is None else num_samples
|
490 |
+
|
491 |
+
# distribution of classes in the dataset
|
492 |
+
df = pd.DataFrame()
|
493 |
+
df["label"] = self._get_labels(dataset)
|
494 |
+
df.index = self.indices
|
495 |
+
df = df.sort_index()
|
496 |
+
|
497 |
+
label_to_count = df["label"].value_counts()
|
498 |
+
label_to_count[1] = int(label_to_count[1] / ratio)
|
499 |
+
|
500 |
+
weights = 1.0 / label_to_count[df["label"]]
|
501 |
+
|
502 |
+
self.weights = torch.DoubleTensor(weights.to_list())
|
503 |
+
|
504 |
+
def _get_labels(self, dataset):
|
505 |
+
return dataset.get_labels()
|
506 |
+
|
507 |
+
def __iter__(self):
|
508 |
+
if self.constantSeed:
|
509 |
+
torch.random.manual_seed(1234)
|
510 |
+
return (self.indices[i] for i in torch.multinomial(self.weights, self.num_samples, replacement=True))
|
511 |
+
|
512 |
+
def __len__(self):
|
513 |
+
return self.num_samples
|
efficientdet_comparison/coco_eval.py
ADDED
@@ -0,0 +1,301 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
###########################################################################
|
2 |
+
# Computer vision - Embedded person tracking demo software by HyperbeeAI. #
|
3 |
+
# Copyrights © 2023 Hyperbee.AI Inc. All rights reserved. main@shallow.ai #
|
4 |
+
###########################################################################
|
5 |
+
# Author: Zylo117
|
6 |
+
|
7 |
+
"""
|
8 |
+
COCO-Style Evaluations
|
9 |
+
|
10 |
+
put images here datasets/your_project_name/val_set_name/*.jpg
|
11 |
+
put annotations here datasets/your_project_name/annotations/instances_{val_set_name}.json
|
12 |
+
put weights here /path/to/your/weights/*.pth
|
13 |
+
change compound_coef
|
14 |
+
|
15 |
+
"""
|
16 |
+
|
17 |
+
import json
|
18 |
+
import os
|
19 |
+
import numpy as np
|
20 |
+
|
21 |
+
import argparse
|
22 |
+
import torch
|
23 |
+
from tqdm import tqdm
|
24 |
+
from pycocotools.coco import COCO
|
25 |
+
from pycocotools.cocoeval import COCOeval
|
26 |
+
from torch.utils.data import DataLoader
|
27 |
+
import torchvision
|
28 |
+
import torchvision.transforms as transforms
|
29 |
+
import time
|
30 |
+
|
31 |
+
from models import mnv2_SSDlite
|
32 |
+
from library.ssd import conv_model_fptunc2fpt, conv_model_fpt2qat, conv_model_qat2hw, collate_fn, PredsPostProcess, round_floats
|
33 |
+
from dataloader import CocoDetection, input_fxpt_normalize
|
34 |
+
|
35 |
+
#from library.ssd import generateAnchorsInOrigImage, collate_fn, point_form, prepareHeadDataforLoss_fast, plot_image_mnv2_2xSSDlite, sampleRandomPicsFromCOCO, saveOutputs ,PredsPostProcess, calculatemAP, batchNormAdaptation, round_floats
|
36 |
+
|
37 |
+
ap = argparse.ArgumentParser()
|
38 |
+
ap.add_argument('-m', '--mode', type=str, default='qat', help='Mode of the model, allowed modes: fpt_unc, fpt, qat')
|
39 |
+
ap.add_argument('--nms_threshold', type=float, default=0.5, help='non max supression threshold')
|
40 |
+
ap.add_argument('--conf_threshold', type=float, default=0.5, help='confidence treshold, predictions below this level will be discarded')
|
41 |
+
ap.add_argument('-dp', '--data_path', type=str, default=None, help='/path/to/images')
|
42 |
+
ap.add_argument('-ap', '--json_path', type=str, default=None, help='/path/to/annotations.json')
|
43 |
+
ap.add_argument('-wp', '--weights_path', type=str, default=None, help='/path/to/weights')
|
44 |
+
|
45 |
+
args = ap.parse_args()
|
46 |
+
|
47 |
+
mode = args.mode
|
48 |
+
nms_threshold = args.nms_threshold
|
49 |
+
conf_threshold = args.conf_threshold
|
50 |
+
data_path = args.data_path
|
51 |
+
json_path = args.json_path
|
52 |
+
weights_path = args.weights_path
|
53 |
+
|
54 |
+
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
55 |
+
|
56 |
+
def evaluate_coco(model, DATA_PATH, JSON_PATH , nmsIoUTreshold = 0.5, PredMinConfTreshold = 0.5, HW_mode = False):
|
57 |
+
|
58 |
+
if HW_mode:
|
59 |
+
act_8b_mode = True
|
60 |
+
else:
|
61 |
+
act_8b_mode = False
|
62 |
+
|
63 |
+
transform = transforms.Compose([transforms.ToTensor(), input_fxpt_normalize(act_8b_mode=act_8b_mode)])
|
64 |
+
targetFileName = 'resized.json'
|
65 |
+
dataset = CocoDetection(root=DATA_PATH, annFile=JSON_PATH, transform=transform, scaleImgforCrop= None)
|
66 |
+
|
67 |
+
dataset.createResizedAnnotJson(targetFileName=targetFileName)
|
68 |
+
resizedFilePath = os.path.join(os.path.split(JSON_PATH)[0],targetFileName)
|
69 |
+
cocoGt=COCO(resizedFilePath)
|
70 |
+
os.remove(resizedFilePath)
|
71 |
+
|
72 |
+
seq_sampler = torch.utils.data.SequentialSampler(dataset)
|
73 |
+
data_loader = DataLoader(dataset,
|
74 |
+
sampler=seq_sampler,
|
75 |
+
batch_size=1,
|
76 |
+
collate_fn=collate_fn,
|
77 |
+
drop_last=False)
|
78 |
+
print(f"Dataset Length: {len(dataset)}, Number of Batches: {len(data_loader)}")
|
79 |
+
|
80 |
+
ANCHORS_HEAD1 = [(11.76, 28.97),
|
81 |
+
(20.98, 52.03),
|
82 |
+
(29.91, 77.24),
|
83 |
+
(38.97, 106.59)]
|
84 |
+
|
85 |
+
ANCHORS_HEAD2 = [(52.25, 144.77),
|
86 |
+
(65.86, 193.05),
|
87 |
+
(96.37, 254.09),
|
88 |
+
(100.91, 109.82),
|
89 |
+
(140, 350)]
|
90 |
+
|
91 |
+
predsPostProcess = PredsPostProcess(512, ANCHORS_HEAD1, ANCHORS_HEAD2)
|
92 |
+
|
93 |
+
|
94 |
+
dataDictList =[]
|
95 |
+
imgIDS = []
|
96 |
+
for i, data in enumerate(tqdm(data_loader)):
|
97 |
+
imageBatch, targetBatch , idxBatch = data
|
98 |
+
|
99 |
+
imageStack = torch.stack(imageBatch).detach().to(device)
|
100 |
+
imageStack.requires_grad_(True)
|
101 |
+
predBatch = model(imageStack)
|
102 |
+
|
103 |
+
if HW_mode:
|
104 |
+
BBs1 = predBatch[0].detach() / 128.0
|
105 |
+
CFs1 = predBatch[1].detach() / 128.0
|
106 |
+
BBs2 = predBatch[2].detach() / 128.0
|
107 |
+
CFs2 = predBatch[3].detach() / 128.0
|
108 |
+
else:
|
109 |
+
BBs1 = predBatch[0].detach()
|
110 |
+
CFs1 = predBatch[1].detach()
|
111 |
+
BBs2 = predBatch[2].detach()
|
112 |
+
CFs2 = predBatch[3].detach()
|
113 |
+
|
114 |
+
for imgNum in range(imageStack.shape[0]):
|
115 |
+
img = imageStack[imgNum,:,:,:]
|
116 |
+
target = targetBatch[imgNum]
|
117 |
+
image_id = int(idxBatch[imgNum])
|
118 |
+
imgIDS.append(image_id)
|
119 |
+
|
120 |
+
pred = (BBs1[imgNum,:,:,:].unsqueeze(0), CFs1[imgNum,:,:,:].unsqueeze(0),
|
121 |
+
BBs2[imgNum,:,:,:].unsqueeze(0), CFs2[imgNum,:,:,:].unsqueeze(0))
|
122 |
+
|
123 |
+
boxes, confidences = predsPostProcess.getPredsInOriginal(pred)
|
124 |
+
|
125 |
+
nms_picks = torchvision.ops.nms(boxes, confidences, nmsIoUTreshold)
|
126 |
+
boxes_to_draw = boxes[nms_picks]
|
127 |
+
confs_to_draw = confidences[nms_picks]
|
128 |
+
confMask = (confs_to_draw > PredMinConfTreshold)
|
129 |
+
|
130 |
+
# Inputs to mAP algorithm
|
131 |
+
if (confMask.any()):
|
132 |
+
|
133 |
+
# pred boxes -> [xmin,ymin,xmax,ymax], tensor shape[numpred,4]
|
134 |
+
bbox = boxes_to_draw[confMask]
|
135 |
+
scores = confs_to_draw[confMask]
|
136 |
+
# Convert BB to coco annot format -> [xmin,ymin,width, height]
|
137 |
+
bbox[:,2] = bbox[:,2] - bbox[:,0]
|
138 |
+
bbox[:,3] = bbox[:,3] - bbox[:,1]
|
139 |
+
|
140 |
+
|
141 |
+
bbox = bbox.tolist() # pred boxes -> [xmin,ymin,xmax,ymax], shape[numpred,4]
|
142 |
+
score = scores.tolist()
|
143 |
+
category_id = np.ones_like(score,dtype=int).tolist()
|
144 |
+
|
145 |
+
for j in range(len(bbox)):
|
146 |
+
box = {"image_id":image_id, "category_id":category_id[j], "bbox":bbox[j],"score":score[j]}
|
147 |
+
dataDictList.append(round_floats(box))
|
148 |
+
|
149 |
+
if (len(dataDictList)):
|
150 |
+
# Evavluate and Accumulate mAP for remained baches, if any
|
151 |
+
cocoDT = json.dumps(dataDictList)
|
152 |
+
|
153 |
+
# Write detections to .json file
|
154 |
+
with open('cocoDT.json', 'w') as outfile:
|
155 |
+
outfile.write(cocoDT)
|
156 |
+
|
157 |
+
# Load detections
|
158 |
+
cocoDt=cocoGt.loadRes('cocoDT.json')
|
159 |
+
os.remove("cocoDT.json")
|
160 |
+
|
161 |
+
# running evaluation
|
162 |
+
annType = 'bbox'
|
163 |
+
cocoEval = COCOeval(cocoGt,cocoDt,annType)
|
164 |
+
cocoEval.params.catIds = 1
|
165 |
+
cocoEval.params.imgIds = imgIDS
|
166 |
+
cocoEval.evaluate()
|
167 |
+
cocoEval.accumulate()
|
168 |
+
|
169 |
+
print('')
|
170 |
+
cocoEval.summarize()
|
171 |
+
else:
|
172 |
+
raise Exception('the model does not provide any valid output, check model architecture and the data input')
|
173 |
+
|
174 |
+
|
175 |
+
if __name__ == '__main__':
|
176 |
+
model = mnv2_SSDlite()
|
177 |
+
|
178 |
+
layer_bits_dictionary = {}
|
179 |
+
layer_bits_dictionary['conv1' ] = 8;
|
180 |
+
layer_bits_dictionary['epw_conv2' ] = 8;
|
181 |
+
layer_bits_dictionary['dw_conv2' ] = 8;
|
182 |
+
layer_bits_dictionary['ppw_conv2' ] = 8;
|
183 |
+
|
184 |
+
layer_bits_dictionary['epw_conv3' ] = 8;
|
185 |
+
layer_bits_dictionary['dw_conv3' ] = 8;
|
186 |
+
layer_bits_dictionary['ppw_conv3' ] = 8;
|
187 |
+
|
188 |
+
layer_bits_dictionary['epw_conv4' ] = 8;
|
189 |
+
layer_bits_dictionary['dw_conv4' ] = 8;
|
190 |
+
layer_bits_dictionary['ppw_conv4' ] = 8;
|
191 |
+
|
192 |
+
layer_bits_dictionary['epw_conv5'] = 8;
|
193 |
+
layer_bits_dictionary['dw_conv5'] = 8;
|
194 |
+
layer_bits_dictionary['ppw_conv5'] = 8;
|
195 |
+
|
196 |
+
layer_bits_dictionary['epw_conv6'] = 8;
|
197 |
+
layer_bits_dictionary['dw_conv6'] = 8;
|
198 |
+
layer_bits_dictionary['ppw_conv6'] = 8;
|
199 |
+
|
200 |
+
layer_bits_dictionary['epw_conv7'] = 8;
|
201 |
+
layer_bits_dictionary['dw_conv7'] = 8;
|
202 |
+
layer_bits_dictionary['ppw_conv7'] = 8;
|
203 |
+
|
204 |
+
layer_bits_dictionary['epw_conv8'] = 8;
|
205 |
+
layer_bits_dictionary['dw_conv8'] = 8;
|
206 |
+
layer_bits_dictionary['ppw_conv8'] = 8;
|
207 |
+
|
208 |
+
layer_bits_dictionary['epw_conv9'] = 8;
|
209 |
+
layer_bits_dictionary['dw_conv9'] = 8;
|
210 |
+
layer_bits_dictionary['ppw_conv9'] = 8;
|
211 |
+
|
212 |
+
layer_bits_dictionary['epw_conv10'] = 8;
|
213 |
+
layer_bits_dictionary['dw_conv10'] = 8;
|
214 |
+
layer_bits_dictionary['ppw_conv10'] = 8;
|
215 |
+
|
216 |
+
layer_bits_dictionary['epw_conv11'] = 8;
|
217 |
+
layer_bits_dictionary['dw_conv11'] = 8;
|
218 |
+
layer_bits_dictionary['ppw_conv11'] = 8;
|
219 |
+
|
220 |
+
layer_bits_dictionary['epw_conv12'] = 8;
|
221 |
+
layer_bits_dictionary['dw_conv12'] = 8;
|
222 |
+
layer_bits_dictionary['ppw_conv12'] = 8;
|
223 |
+
|
224 |
+
layer_bits_dictionary['epw_conv13'] = 8;
|
225 |
+
layer_bits_dictionary['dw_conv13'] = 8;
|
226 |
+
layer_bits_dictionary['ppw_conv13'] = 8;
|
227 |
+
|
228 |
+
layer_bits_dictionary['epw_conv14'] = 8;
|
229 |
+
layer_bits_dictionary['dw_conv14'] = 8;
|
230 |
+
layer_bits_dictionary['ppw_conv14'] = 8;
|
231 |
+
|
232 |
+
layer_bits_dictionary['epw_conv15'] = 8;
|
233 |
+
layer_bits_dictionary['dw_conv15'] = 8;
|
234 |
+
layer_bits_dictionary['ppw_conv15'] = 8;
|
235 |
+
|
236 |
+
layer_bits_dictionary['epw_conv16'] = 8;
|
237 |
+
layer_bits_dictionary['dw_conv16'] = 8;
|
238 |
+
layer_bits_dictionary['ppw_conv16'] = 8;
|
239 |
+
|
240 |
+
layer_bits_dictionary['epw_conv17'] = 8;
|
241 |
+
layer_bits_dictionary['dw_conv17'] = 8;
|
242 |
+
layer_bits_dictionary['ppw_conv17'] = 8;
|
243 |
+
|
244 |
+
layer_bits_dictionary['epw_conv18'] = 8;
|
245 |
+
layer_bits_dictionary['dw_conv18'] = 8;
|
246 |
+
layer_bits_dictionary['ppw_conv18'] = 8;
|
247 |
+
|
248 |
+
layer_bits_dictionary['head1_dw_classification'] = 8;
|
249 |
+
layer_bits_dictionary['head1_pw_classification'] = 8;
|
250 |
+
layer_bits_dictionary['head1_dw_regression'] = 8;
|
251 |
+
layer_bits_dictionary['head1_pw_regression'] = 8;
|
252 |
+
|
253 |
+
layer_bits_dictionary['head2_dw_classification'] = 8;
|
254 |
+
layer_bits_dictionary['head2_pw_classification'] = 8;
|
255 |
+
layer_bits_dictionary['head2_dw_regression'] = 8;
|
256 |
+
layer_bits_dictionary['head2_pw_regression'] = 8;
|
257 |
+
|
258 |
+
# Convert model to appropriate mode before loading weights
|
259 |
+
HW_mode = False
|
260 |
+
if mode == 'fpt_unc':
|
261 |
+
model.to(device)
|
262 |
+
|
263 |
+
elif mode == 'fpt':
|
264 |
+
model = conv_model_fptunc2fpt(model)
|
265 |
+
model.to(device)
|
266 |
+
|
267 |
+
elif mode == 'qat':
|
268 |
+
model = conv_model_fptunc2fpt(model)
|
269 |
+
model.to(device)
|
270 |
+
model = conv_model_fpt2qat(model, layer_bits_dictionary)
|
271 |
+
model.to(device)
|
272 |
+
|
273 |
+
elif mode == 'hw':
|
274 |
+
HW_mode = True
|
275 |
+
model = conv_model_fptunc2fpt(model)
|
276 |
+
model.to(device)
|
277 |
+
model = conv_model_fpt2qat(model, layer_bits_dictionary)
|
278 |
+
model.to(device)
|
279 |
+
model = conv_model_qat2hw(model)
|
280 |
+
model.to(device)
|
281 |
+
|
282 |
+
else:
|
283 |
+
raise Exception('Invalid model mode is selected, select from: fpt_unc, fpt, qat, hw')
|
284 |
+
|
285 |
+
|
286 |
+
weights = torch.load(weights_path, map_location=torch.device('cpu'))
|
287 |
+
model.load_state_dict(weights['state_dict'], strict=True)
|
288 |
+
|
289 |
+
model.requires_grad_(False)
|
290 |
+
model.eval()
|
291 |
+
|
292 |
+
if mode == 'qat' or mode == 'hw':
|
293 |
+
print(''*5)
|
294 |
+
print('*'*120)
|
295 |
+
print('qat or hardware mode is selected, please make sure you configured layer_bits_dictionary in "coco_eval.py" accordingly!!!')
|
296 |
+
print('*'*120)
|
297 |
+
print('')
|
298 |
+
time.sleep(5)
|
299 |
+
|
300 |
+
evaluate_coco(model, DATA_PATH=data_path, JSON_PATH=json_path , nmsIoUTreshold=nms_threshold,
|
301 |
+
PredMinConfTreshold=conf_threshold, HW_mode = HW_mode)
|
efficientdet_comparison/hardware_experiment_best.pth.tar
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:e4712fd8026f221b6a40f464438821858389a7a9d021da6c4f2ddb881d7a695e
|
3 |
+
size 7481103
|
efficientdet_comparison/readme.md
ADDED
@@ -0,0 +1,186 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Performance Benchmark of Quantized Detection Model
|
2 |
+
|
3 |
+
This directory is built for comparison of our "quantized / quantization aware trained" detection algorithm to one of the SOTA compact detection algorithms, EfficientDet-d0, which has comparable complexity and structure with our quantized model.
|
4 |
+
|
5 |
+
Our person tracking algorithm uses MobileNet-v2 as backbone mechanism and combines it with 2 SSD heads using total of 9 anchor boxes. Overall model consists of 60 convolution layers.
|
6 |
+
|
7 |
+
We quantized the layers of this model and applied "quantization aware training" methods to recover its accuracy drop due to quantization of layers and output clamping. We have re-scaled and center cropped the images in [Wider Person Dataset](https://competitions.codalab.org/competitions/20132#learn_the_details), also we resized its annotations and converted in to COCO annotation format to use them in our training/evaluation tasks. Then we applied smart training approaches which consider the effects of quantization and output clamping of the layers during optimization, which we call "quantization aware training".
|
8 |
+
|
9 |
+
Our main motivation of quantizing networks and applying quantization aware training methods is to reduce the overall network size, inference time and training effort while keeping accuracy drop in an acceptable level. We aim to develop quantized compact detection algorithms executable on low power and low cost accelerator chips.
|
10 |
+
|
11 |
+
## Dependencies
|
12 |
+
* [PyTorch](https://github.com/pytorch/pytorch)
|
13 |
+
* [Torchvision](https://github.com/pytorch/vision)
|
14 |
+
* [Pycocotools](https://github.com/cocodataset/cocoapi/tree/master/PythonAPI/pycocotools)
|
15 |
+
* [webcolors](https://pypi.org/project/webcolors/)
|
16 |
+
* [PyYAML](https://github.com/yaml/pyyaml)
|
17 |
+
|
18 |
+
## Evaluating EfficientDet with Wider Person Validation Dataset
|
19 |
+
In this section, steps to reproduce the evaluation of EfficientDet model from [Yet-Another-EfficientDet-Pytorch Repository](https://github.com/zylo117/Yet-Another-EfficientDet-Pytorch.git) with d0 coefficients is explained. For evaluation, aforementioned Wider Person Validation Dataset in COCO format is used.
|
20 |
+
|
21 |
+
### 1. Clone EfficientDet to Your Local
|
22 |
+
Open a terminal and go to directory in your local where you want to clone , then type:
|
23 |
+
```bash
|
24 |
+
git clone --depth 1 https://github.com/zylo117/Yet-Another-EfficientDet-Pytorch
|
25 |
+
```
|
26 |
+
|
27 |
+
### 2. Prepare EfficientDet-d0 Coefficients
|
28 |
+
* Go to main directory
|
29 |
+
```bash
|
30 |
+
cd Yet-Another-EfficientDet-Pytorch/
|
31 |
+
```
|
32 |
+
* Create weights folder
|
33 |
+
```bash
|
34 |
+
mkdir weights
|
35 |
+
```
|
36 |
+
* Download EfficientDet d0 coefficients
|
37 |
+
```bash
|
38 |
+
wget https://github.com/zylo117/Yet-Another-EfficientDet-Pytorch/releases/download/1.0/efficientdet-d0.pth -O weights/efficientdet-d0.pth
|
39 |
+
```
|
40 |
+
|
41 |
+
### 3. Prepare Wider Person Dataset
|
42 |
+
* Download original Wider Person Dataset
|
43 |
+
* Sign up [Codalab](https://competitions.codalab.org/) and participate to [WIDER Face & Person Challenge 2019](https://competitions.codalab.org/competitions/20132)
|
44 |
+
* Under "Participate" tab click "Train & Validation Data in Google Drive" and download
|
45 |
+
* val_data.tar.gz
|
46 |
+
* Annotations/val_bbox.txt
|
47 |
+
* Extract val_data.tar.gz as val_data and move val_data folder under ./data/original_wider/val_data
|
48 |
+
* Move "val_bbox.txt" under ./data/original_wider/
|
49 |
+
|
50 |
+
* Move our "wider2coco.py" script in "efficientdet_comparison" folder to main folder of your local "Yet-Another-EfficientDet-Pytorch" repository. Following code will produce resized images and annotations.
|
51 |
+
```bash
|
52 |
+
python wider2coco.py -ip ./data/original_wider/val_data -af ./data/original_wider/val_bbox.txt
|
53 |
+
```
|
54 |
+
* Script will automatically convert Wider Dataset in to COCO format and create following repository structure:
|
55 |
+
|
56 |
+
./Yet-Another-EfficientDet-Pytorch/datasets/wider/val
|
57 |
+
image001.jpg
|
58 |
+
image002.jpg
|
59 |
+
...
|
60 |
+
./Yet-Another-EfficientDet-Pytorch/datasets/wider/annotations
|
61 |
+
instances_val.json
|
62 |
+
|
63 |
+
|
64 |
+
|
65 |
+
### 4. Manually Set Project's Specific Parameters
|
66 |
+
|
67 |
+
* Create a yml file "wider.yml" under "projects"
|
68 |
+
```bash
|
69 |
+
touch projects/wider.yml
|
70 |
+
```
|
71 |
+
|
72 |
+
* Copy following content in to "wider.yml" file
|
73 |
+
|
74 |
+
project_name: wider
|
75 |
+
train_set: train
|
76 |
+
val_set: val
|
77 |
+
num_gpus: 1 # 0 means using cpu, 1-N means using gpus
|
78 |
+
|
79 |
+
# Wider validation dataset mean and std in RGB order
|
80 |
+
mean: [0.416, 0.413, 0.406]
|
81 |
+
std: [0.308, 0.306, 0.310]
|
82 |
+
|
83 |
+
# this is coco anchors, change it if necessary
|
84 |
+
anchors_scales: '[2 ** 0, 2 ** (1.0 / 3.0), 2 ** (2.0 / 3.0)]'
|
85 |
+
anchors_ratios: '[(1.0, 1.0), (1.4, 0.7), (0.7, 1.4)]'
|
86 |
+
|
87 |
+
# objects from all labels from your dataset with the order from your annotations.
|
88 |
+
# its index must match your dataset's category_id.
|
89 |
+
# category_id is one_indexed,
|
90 |
+
# for example, index of 'car' here is 2, while category_id of is 3
|
91 |
+
obj_list: ['person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light', 'fire hydrant', '', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', '', 'backpack', 'umbrella', '', '', 'handbag', 'tie', 'suitcase', 'frisbee', 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', 'bottle', '', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', 'potted plant', 'bed', '', 'dining table', '', '', 'toilet', '', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', 'oven', 'toaster', 'sink', 'refrigerator', '', 'book', 'clock', 'vase', 'scissors','teddy bear', 'hair drier', 'toothbrush']
|
92 |
+
|
93 |
+
### 5. Evaluate EfficientDet model performance
|
94 |
+
* Setup "person only evaluation"
|
95 |
+
* Open "coco_eval.py" under <parent directory>/Yet-Another-EfficientDet-Pytorch
|
96 |
+
* Paste following code after line 132, "coco_eval.params.imgIds = image_ids", to evaluate mAP results only for person category
|
97 |
+
```python
|
98 |
+
coco_eval.params.catIds = 1
|
99 |
+
```
|
100 |
+
|
101 |
+
* For evaluation on cuda enabled platform
|
102 |
+
```bash
|
103 |
+
python coco_eval.py -p wider -c 0 -w ./weights/efficientdet-d0.pth
|
104 |
+
```
|
105 |
+
|
106 |
+
* For evaluation on cuda disabled platform
|
107 |
+
```bash
|
108 |
+
python coco_eval.py -p wider -c 0 -w ./weights/efficientdet-d0.pth --cuda False
|
109 |
+
```
|
110 |
+
|
111 |
+
|
112 |
+
## Evaluating Our Quantized MobilenetSSDLite model with Wider Person Validation Dataset
|
113 |
+
|
114 |
+
### 1. Clone Quantized Mobilenet Model to Your Local
|
115 |
+
Open a terminal and go to directory in your local where you want to clone our [Quantization Aware Training - Person Tracking](https://github.com/sai-tr/persontracking_qat.git) repository, then type:
|
116 |
+
```bash
|
117 |
+
git clone --depth 1 https://github.com/sai-tr/persontracking_qat.git
|
118 |
+
```
|
119 |
+
|
120 |
+
### 2. Prepare Wider Person Dataset
|
121 |
+
* Download original Wider Person Dataset
|
122 |
+
* Sign up [Codalab](https://competitions.codalab.org/) and participate to [WIDER Face & Person Challenge 2019](https://competitions.codalab.org/competitions/20132)
|
123 |
+
* Under "Participate" tab click "Train & Validation Data in Google Drive" and download
|
124 |
+
* val_data.tar.gz
|
125 |
+
* Annotations/val_bbox.txt
|
126 |
+
* Extract val_data.tar.gz as val_data and move val_data folder under ./data/original_wider/val_data
|
127 |
+
* Move "val_bbox.txt" under ./data/original_wider/
|
128 |
+
|
129 |
+
* Move our "wider2coco.py" script in "efficientdet_comparison" folder to main folder of your local "persontracking_qat" repository. Following code will produce resized images and annotations.
|
130 |
+
```bash
|
131 |
+
python wider2coco.py -ip ./data/original_wider/val_data -af ./data/original_wider/val_bbox.txt
|
132 |
+
```
|
133 |
+
* Script will automatically convert Wider Dataset in to COCO format and create following repository structure:
|
134 |
+
|
135 |
+
./persontracking_qat/datasets/wider/val
|
136 |
+
image001.jpg
|
137 |
+
image002.jpg
|
138 |
+
...
|
139 |
+
./persontracking_qat/datasets/wider/annotations
|
140 |
+
instances_val.json
|
141 |
+
|
142 |
+
### 3. Evaluate Quantized Mobilenet Model Performance
|
143 |
+
Note that model mode should match with the loaded model parameter dictionary. Selectable model modes are:
|
144 |
+
* Full Precision Unconstrained(fpt_unc): All layers are in full precision and no output clamping
|
145 |
+
* Full Precision Constrained(fpt): All layers are in full precision and layer output are clamped to +-1
|
146 |
+
* Quantized(qat): All layers are quantized layer outputs are clamped to +-1
|
147 |
+
|
148 |
+
|
149 |
+
* Move our "coco_eval.py" script in "efficientdet_comparison" folder to "persontracking_qat" folder and use following command for evaluation:
|
150 |
+
```bash
|
151 |
+
python coco_eval.py -m qat -dp ./datasets/wider/val -ap ./datasets/wider/annotations/all_val_prep.json -wp ./efficientdet_comparison/training_experiment_best.pth.tar
|
152 |
+
```
|
153 |
+
Note that: Code evaluates quantized model with weights "training_experiment_best.pth.tar", using images and annotations in paths "./datasets/wider/val" "./datasets/wider/annotations/instances_val.json" respectively.
|
154 |
+
|
155 |
+
## mAP Comparisons
|
156 |
+
### EfficientDet-d0
|
157 |
+
### Wider Validation Dataset mAP scores ###
|
158 |
+
Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.292
|
159 |
+
Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.543
|
160 |
+
Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.275
|
161 |
+
Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.109
|
162 |
+
Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.409
|
163 |
+
Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.532
|
164 |
+
Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.106
|
165 |
+
Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.369
|
166 |
+
Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.435
|
167 |
+
Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.270
|
168 |
+
Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.546
|
169 |
+
Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.678
|
170 |
+
|
171 |
+
|
172 |
+
### Quantized Mobilenet
|
173 |
+
### Wider Validation Dataset mAP scores ###
|
174 |
+
Average Precision (AP) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.281
|
175 |
+
Average Precision (AP) @[ IoU=0.50 | area= all | maxDets=100 ] = 0.457
|
176 |
+
Average Precision (AP) @[ IoU=0.75 | area= all | maxDets=100 ] = 0.310
|
177 |
+
Average Precision (AP) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.075
|
178 |
+
Average Precision (AP) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.406
|
179 |
+
Average Precision (AP) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.582
|
180 |
+
Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 1 ] = 0.107
|
181 |
+
Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets= 10 ] = 0.324
|
182 |
+
Average Recall (AR) @[ IoU=0.50:0.95 | area= all | maxDets=100 ] = 0.331
|
183 |
+
Average Recall (AR) @[ IoU=0.50:0.95 | area= small | maxDets=100 ] = 0.110
|
184 |
+
Average Recall (AR) @[ IoU=0.50:0.95 | area=medium | maxDets=100 ] = 0.481
|
185 |
+
Average Recall (AR) @[ IoU=0.50:0.95 | area= large | maxDets=100 ] = 0.637
|
186 |
+
|
efficientdet_comparison/training_experiment_best.pth.tar
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:79dbbd0f1849c213da61f71985dce57a88b7cd03881cd093a44b3daab61902f4
|
3 |
+
size 7480143
|
efficientdet_comparison/wider2coco.py
ADDED
@@ -0,0 +1,577 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
###########################################################################
|
2 |
+
# Computer vision - Embedded person tracking demo software by HyperbeeAI. #
|
3 |
+
# Copyrights © 2023 Hyperbee.AI Inc. All rights reserved. main@shallow.ai #
|
4 |
+
###########################################################################
|
5 |
+
import os
|
6 |
+
import datetime, time
|
7 |
+
import json
|
8 |
+
from PIL import Image
|
9 |
+
from tqdm import tqdm
|
10 |
+
|
11 |
+
import torch, torchvision
|
12 |
+
from torchvision import transforms
|
13 |
+
from torchvision.datasets.vision import VisionDataset
|
14 |
+
|
15 |
+
from typing import Any, Callable, Optional, Tuple, List
|
16 |
+
import argparse
|
17 |
+
|
18 |
+
##############################################################################
|
19 |
+
####################### Functions to Prepare Images ##########################
|
20 |
+
##############################################################################
|
21 |
+
# Functions defined for prescaling images/targets before center crop operation
|
22 |
+
def calcPrescale(image_width, image_height, scaleImgforCrop = 512):
|
23 |
+
# Calculate scale factor to shrink/expand image to coincide width or height to croppig area
|
24 |
+
scale = 1.0
|
25 |
+
# image fully encapsulates cropping area or vice versa
|
26 |
+
if ((image_width-scaleImgforCrop)*(image_height-scaleImgforCrop) > 0):
|
27 |
+
# if width of original image is closer to crop area
|
28 |
+
if abs(1-image_width/scaleImgforCrop) < abs(1-image_height/scaleImgforCrop):
|
29 |
+
scale = image_width/scaleImgforCrop
|
30 |
+
else:
|
31 |
+
scale = image_height/scaleImgforCrop
|
32 |
+
return scale
|
33 |
+
|
34 |
+
|
35 |
+
# Scales the image with defined scale
|
36 |
+
def prescaleImage(image, scale):
|
37 |
+
|
38 |
+
image_width = int(image.size[0]/scale)
|
39 |
+
image_height = int(image.size[1]/scale)
|
40 |
+
|
41 |
+
|
42 |
+
image_res = image.resize((image_width, image_height))
|
43 |
+
return image_res
|
44 |
+
|
45 |
+
|
46 |
+
def preProcessImages(org_images_path):
|
47 |
+
corruptedImgs = []
|
48 |
+
ccrop_size = 512
|
49 |
+
folder_dir,folder_name = os.path.split(org_images_path)
|
50 |
+
cur_dir = os.getcwd()
|
51 |
+
|
52 |
+
processed_images_path = os.path.join(cur_dir,'datasets','wider','val')
|
53 |
+
|
54 |
+
if not os.path.isdir(processed_images_path):
|
55 |
+
os.makedirs(processed_images_path)
|
56 |
+
imageNames = os.listdir(org_images_path)
|
57 |
+
|
58 |
+
for i, image in enumerate(tqdm(imageNames)):
|
59 |
+
try:
|
60 |
+
if(image.split('.')[1] == 'jpg'):
|
61 |
+
imgDir = os.path.join(org_images_path,image)
|
62 |
+
img = Image.open(imgDir)
|
63 |
+
|
64 |
+
# prescaling
|
65 |
+
image_width = img.size[0]
|
66 |
+
image_height = img.size[1]
|
67 |
+
scale = calcPrescale(image_width, image_height,scaleImgforCrop=ccrop_size)
|
68 |
+
img_resized = prescaleImage(img, scale)
|
69 |
+
|
70 |
+
# Center Crop
|
71 |
+
width, height = img_resized.size # Get dimensions
|
72 |
+
|
73 |
+
left = (width - ccrop_size)/2
|
74 |
+
top = (height - ccrop_size)/2
|
75 |
+
right = (width + ccrop_size)/2
|
76 |
+
bottom = (height + ccrop_size)/2
|
77 |
+
|
78 |
+
# Crop the center of the image
|
79 |
+
img_ccropped = img_resized.crop((left, top, right, bottom))
|
80 |
+
img_ccropped.save(os.path.join(processed_images_path, image))
|
81 |
+
except:
|
82 |
+
print('Cannot Load: ' + image + ', check if it is corrupted.')
|
83 |
+
corruptedImgs.append(image)
|
84 |
+
|
85 |
+
print('')
|
86 |
+
print('Conversion Finished')
|
87 |
+
print('')
|
88 |
+
if len(corruptedImgs):
|
89 |
+
print('Something wrong with the following images and they are not processed:')
|
90 |
+
print(corruptedImgs)
|
91 |
+
print('Please delete these images from associated annotations')
|
92 |
+
return
|
93 |
+
|
94 |
+
|
95 |
+
##############################################################################
|
96 |
+
##################### Functions to Prepare Annotations #######################
|
97 |
+
##############################################################################
|
98 |
+
class CocoDetection(VisionDataset):
|
99 |
+
"""`MS Coco Detection <https://cocodataset.org/#detection-2016>`_ Dataset.
|
100 |
+
Args:
|
101 |
+
root (string): Root directory where images are downloaded to.
|
102 |
+
|
103 |
+
annFile (string): Path to json annotation file.
|
104 |
+
|
105 |
+
scaleImgforCrop (int, optional): Img and target BBs are scaled with
|
106 |
+
constant aspect ratio st:
|
107 |
+
if image width, image height > scaleImgforCrop image is shrinked
|
108 |
+
until width or height becomes equal to scaleImgforCrop
|
109 |
+
|
110 |
+
if image width, image height < scaleImgforCrop image is expanded
|
111 |
+
until width or height becomes equal to scaleImgforCrop
|
112 |
+
|
113 |
+
else no scaling
|
114 |
+
transform (callable, optional): A function/transform that takes in an
|
115 |
+
PIL image and returns a transformed version. E.g, ``transforms.ToTensor``
|
116 |
+
|
117 |
+
target_transform (callable, optional): A function/transform that takes in
|
118 |
+
the target and transforms it.
|
119 |
+
transforms (callable, optional): A function/transform that takes input
|
120 |
+
sample and its target as entry and returns a transformed version.
|
121 |
+
"""
|
122 |
+
|
123 |
+
def __init__(
|
124 |
+
self,
|
125 |
+
root: str,
|
126 |
+
annFile: str,
|
127 |
+
scaleImgforCrop: int= None,
|
128 |
+
transform: Optional[Callable] = None,
|
129 |
+
target_transform: Optional[Callable] = None,
|
130 |
+
transforms: Optional[Callable] = None
|
131 |
+
):
|
132 |
+
super().__init__(root, transforms, transform, target_transform)
|
133 |
+
from pycocotools.coco import COCO
|
134 |
+
|
135 |
+
self.coco = COCO(annFile)
|
136 |
+
self.ids = list(sorted(self.coco.imgs.keys()))
|
137 |
+
self.annFilePath = os.path.join('.',annFile)
|
138 |
+
self.catPersonId = self.coco.getCatIds(catNms=['person'])[0]
|
139 |
+
self.scaleImgforCrop = scaleImgforCrop
|
140 |
+
|
141 |
+
def _load_image(self, id: int) -> Image.Image:
|
142 |
+
path = self.coco.loadImgs(id)[0]["file_name"]
|
143 |
+
return Image.open(os.path.join(self.root, path)).convert("RGB")
|
144 |
+
|
145 |
+
def _load_target(self, id) -> List[Any]:
|
146 |
+
return self.coco.loadAnns(self.coco.getAnnIds(id, iscrowd=False))
|
147 |
+
|
148 |
+
def __getitem__(self, index: int) -> Tuple[Any, Any, Any]:
|
149 |
+
|
150 |
+
id = self.ids[index]
|
151 |
+
imgID = id
|
152 |
+
|
153 |
+
try:
|
154 |
+
image = self._load_image(id)
|
155 |
+
except:
|
156 |
+
print(f'********Unable to load image with id: {imgID}********')
|
157 |
+
print('Please check if image is corrupted, and remove it from annotations if necessary.')
|
158 |
+
|
159 |
+
|
160 |
+
target = copy.deepcopy(self._load_target(id)) # deepcopy target list beforecentercrop manip, to be abe to work with same
|
161 |
+
# dateset without reloading it
|
162 |
+
|
163 |
+
image_width = image.size[0]
|
164 |
+
image_height = image.size[1]
|
165 |
+
|
166 |
+
|
167 |
+
# If necesary rescale the image and BBs near the size of planned center crop as much as possible
|
168 |
+
scale = self._calcPrescale(image_width=image_width, image_height=image_height)
|
169 |
+
image = self._prescaleImage(image, scale)
|
170 |
+
|
171 |
+
for i, t in enumerate(target):
|
172 |
+
BB = t['bbox'].copy()
|
173 |
+
scaledBB = self._prescaleBB(BB,scale)
|
174 |
+
target[i]['bbox'] = scaledBB
|
175 |
+
|
176 |
+
|
177 |
+
|
178 |
+
# Image width height after prescaling
|
179 |
+
image_width = image.size[0]
|
180 |
+
image_height = image.size[1]
|
181 |
+
|
182 |
+
# Check if center crop applied
|
183 |
+
centerCropped = False
|
184 |
+
if self.transforms is not None:
|
185 |
+
image, target = self.transforms(image, target)
|
186 |
+
|
187 |
+
# If center crop applied, transform BBs as well
|
188 |
+
for t in self.transforms.transform.transforms:
|
189 |
+
if (type(t) == torchvision.transforms.transforms.CenterCrop):
|
190 |
+
centerCropped = True
|
191 |
+
|
192 |
+
|
193 |
+
|
194 |
+
x_scale = image.size(2) / image_width
|
195 |
+
y_scale = image.size(1) / image_height
|
196 |
+
|
197 |
+
bbox_arr = []
|
198 |
+
|
199 |
+
for idx,ann in enumerate(target):
|
200 |
+
if ann['category_id'] == self.catPersonId:
|
201 |
+
crop_size = image.shape[1]
|
202 |
+
|
203 |
+
if centerCropped:
|
204 |
+
bbox = ann['bbox'].copy()
|
205 |
+
croppedBB = self.cropBBox(bbox, crop_size,image_height,image_width)
|
206 |
+
else:
|
207 |
+
croppedBB = torch.tensor(ann['bbox'])
|
208 |
+
|
209 |
+
if not (croppedBB == None):
|
210 |
+
bbox_arr.append(croppedBB)
|
211 |
+
|
212 |
+
if len(bbox_arr) != 0:
|
213 |
+
bbox_arr = torch.stack(bbox_arr)
|
214 |
+
wh = bbox_arr[:, 2:]
|
215 |
+
xy = bbox_arr[:, :2]
|
216 |
+
|
217 |
+
id_tensor = torch.tensor([id]).unsqueeze(0).expand(bbox_arr.size(0), -1)
|
218 |
+
|
219 |
+
bbox_arr = torch.cat([id_tensor, xy, wh], dim=-1)
|
220 |
+
else:
|
221 |
+
bbox_arr = torch.tensor(bbox_arr)
|
222 |
+
|
223 |
+
|
224 |
+
return image, bbox_arr , imgID
|
225 |
+
|
226 |
+
def __len__(self) -> int:
|
227 |
+
return len(self.ids)
|
228 |
+
|
229 |
+
def get_labels(self):
|
230 |
+
labels = []
|
231 |
+
for id in self.ids:
|
232 |
+
anns = self._load_target(id)
|
233 |
+
person_flag = False
|
234 |
+
for ann in anns:
|
235 |
+
person_flag = ann['category_id'] == self.catPersonId
|
236 |
+
if person_flag == True:
|
237 |
+
break
|
238 |
+
if person_flag == True:
|
239 |
+
labels.append(1)
|
240 |
+
else:
|
241 |
+
labels.append(0)
|
242 |
+
return torch.tensor(labels)
|
243 |
+
|
244 |
+
def get_cat_person_id(self):
|
245 |
+
return self.catPersonId
|
246 |
+
|
247 |
+
def get_coco_api(self):
|
248 |
+
return self.coco
|
249 |
+
|
250 |
+
|
251 |
+
# Functions defined for prescaling images/targets before center crop operation
|
252 |
+
def _calcPrescale(self, image_width, image_height):
|
253 |
+
# Calculate scale factor to shrink/expand image to coincide width or height to croppig area
|
254 |
+
scale = 1.0
|
255 |
+
if self.scaleImgforCrop != None:
|
256 |
+
# image fully encapsulates cropping area or vice versa
|
257 |
+
if ((image_width-self.scaleImgforCrop)*(image_height-self.scaleImgforCrop) > 0):
|
258 |
+
# if width of original image is closer to crop area
|
259 |
+
if abs(1-image_width/self.scaleImgforCrop) < abs(1-image_height/self.scaleImgforCrop):
|
260 |
+
scale = image_width/self.scaleImgforCrop
|
261 |
+
else:
|
262 |
+
scale = image_height/self.scaleImgforCrop
|
263 |
+
return scale
|
264 |
+
|
265 |
+
# Scales the image with defined scale
|
266 |
+
def _prescaleImage(self, image, scale):
|
267 |
+
image_width = int(image.size[0]/scale)
|
268 |
+
image_height = int(image.size[1]/scale)
|
269 |
+
|
270 |
+
t = transforms.Resize([image_height,image_width])
|
271 |
+
image = t(image)
|
272 |
+
return image
|
273 |
+
|
274 |
+
# Scales the targets with defined scale
|
275 |
+
def _prescaleBB(self, BB, scale):
|
276 |
+
scaledbb = [round(p/scale,1) for p in BB]
|
277 |
+
return scaledbb
|
278 |
+
|
279 |
+
|
280 |
+
def cropBBox(self,bbox,crop_size, image_height, image_width):
|
281 |
+
|
282 |
+
bbox_aligned = []
|
283 |
+
x, y, w, h = bbox[0], bbox[1], bbox[2], bbox[3]
|
284 |
+
|
285 |
+
# Casses for cropping
|
286 |
+
if image_height < crop_size:
|
287 |
+
offset = (crop_size - image_height) // 2
|
288 |
+
y = y + offset
|
289 |
+
if (y+h) > crop_size:
|
290 |
+
offset = (y+h)-crop_size
|
291 |
+
h = h - offset
|
292 |
+
if image_width < crop_size:
|
293 |
+
offset = (crop_size - image_width) // 2
|
294 |
+
x = x + offset
|
295 |
+
if (x+w) > crop_size:
|
296 |
+
offset = (x+w)-crop_size
|
297 |
+
w = w - offset
|
298 |
+
if image_width > crop_size:
|
299 |
+
offset = (image_width - crop_size) // 2
|
300 |
+
if offset > x:
|
301 |
+
# Deal with BB coincide with left cropping boundary
|
302 |
+
w = w -(offset-x)
|
303 |
+
x = 0
|
304 |
+
else:
|
305 |
+
x = x - offset
|
306 |
+
|
307 |
+
# Deal with BB coincide with right cropping boundary
|
308 |
+
if (x+w) > crop_size:
|
309 |
+
offset = (x+w)-crop_size
|
310 |
+
w = w - offset
|
311 |
+
|
312 |
+
if image_height > crop_size:
|
313 |
+
|
314 |
+
offset = (image_height - crop_size) // 2
|
315 |
+
if offset > y:
|
316 |
+
# Deal with BB coincide with top cropping boundary
|
317 |
+
h = h -(offset-y)
|
318 |
+
y = 0
|
319 |
+
else:
|
320 |
+
y = y - offset
|
321 |
+
# Deal with BB coincide with bottom cropping boundary
|
322 |
+
if (y+h) > crop_size:
|
323 |
+
offset = (y+h)-crop_size
|
324 |
+
h = h - offset
|
325 |
+
|
326 |
+
bbox_aligned.append(x)
|
327 |
+
bbox_aligned.append(y)
|
328 |
+
bbox_aligned.append(w)
|
329 |
+
bbox_aligned.append(h)
|
330 |
+
|
331 |
+
if ((w <= 0) or (h <= 0)):
|
332 |
+
return None
|
333 |
+
else:
|
334 |
+
x_scale, y_scale = 1.0,1.0
|
335 |
+
return torch.mul(torch.tensor(bbox_aligned), torch.tensor([x_scale, y_scale, x_scale, y_scale]))
|
336 |
+
|
337 |
+
def __round_floats(self,o):
|
338 |
+
'''
|
339 |
+
Used to round floats before writing to json file
|
340 |
+
'''
|
341 |
+
if isinstance(o, float):
|
342 |
+
return round(o, 2)
|
343 |
+
if isinstance(o, dict):
|
344 |
+
return {k: self.__round_floats(v) for k, v in o.items()}
|
345 |
+
if isinstance(o, (list, tuple)):
|
346 |
+
return [self.__round_floats(x) for x in o]
|
347 |
+
return o
|
348 |
+
|
349 |
+
def createResizedAnnotJson(self,targetFileName,cropsize = 512):
|
350 |
+
'''
|
351 |
+
Resizes person annotations after center crop operation and saves as json file to the
|
352 |
+
directory of original annotations with the name "targetFileName"
|
353 |
+
'''
|
354 |
+
t1 = time.time()
|
355 |
+
# Get original json annot file path, and create pah for resized json annot file
|
356 |
+
path, annotfilename = os.path.split(self.annFilePath)
|
357 |
+
resizedAnnotPath = os.path.join(path,targetFileName)
|
358 |
+
|
359 |
+
print('')
|
360 |
+
print(f'Creating Json file for resized annotations: {resizedAnnotPath}')
|
361 |
+
|
362 |
+
|
363 |
+
# Load original annotation json file as dictionary and assign it to resized annot dict
|
364 |
+
with open(self.annFilePath) as json_file:
|
365 |
+
resizedanotDict = json.load(json_file)
|
366 |
+
|
367 |
+
# Original annotations array
|
368 |
+
origannList = resizedanotDict['annotations']
|
369 |
+
|
370 |
+
# Check if center crop applied
|
371 |
+
centerCropped = False
|
372 |
+
if self.transforms is not None:
|
373 |
+
# If center crop applied, transform BBs as well
|
374 |
+
for t in self.transforms.transform.transforms:
|
375 |
+
if (type(t) == torchvision.transforms.transforms.CenterCrop):
|
376 |
+
centerCropped = True
|
377 |
+
|
378 |
+
resizedannList = []
|
379 |
+
for resizedannot in origannList:
|
380 |
+
|
381 |
+
currentcatID = resizedannot['category_id']
|
382 |
+
currentBB = resizedannot['bbox']
|
383 |
+
currentImgID = resizedannot['image_id']
|
384 |
+
|
385 |
+
|
386 |
+
# Get crop size and original image sizes
|
387 |
+
image_width = self.coco.loadImgs(currentImgID)[0]['width']
|
388 |
+
image_height = self.coco.loadImgs(currentImgID)[0]['height']
|
389 |
+
|
390 |
+
# If presclae applied to image, calculate new image width and height
|
391 |
+
scale = self._calcPrescale(image_width=image_width, image_height=image_height)
|
392 |
+
image_width = image_width / scale
|
393 |
+
image_height = image_height / scale
|
394 |
+
|
395 |
+
if currentcatID == self.catPersonId:
|
396 |
+
# if BB is person
|
397 |
+
bbox = resizedannot['bbox'].copy()
|
398 |
+
|
399 |
+
# If prescale appied to image, resize annotations BBs
|
400 |
+
bbox = self._prescaleBB(bbox, scale)
|
401 |
+
|
402 |
+
# If center crop applied, crop/recalculate BBs as well
|
403 |
+
if centerCropped:
|
404 |
+
croppedBB = self.cropBBox(bbox, cropsize,image_height,image_width)
|
405 |
+
else:
|
406 |
+
croppedBB = torch.tensor(bbox)
|
407 |
+
|
408 |
+
if (croppedBB != None):
|
409 |
+
# If BB is person and valid after crop, add it to resized annotations list
|
410 |
+
croppedBB = croppedBB.tolist()
|
411 |
+
resizedannot['bbox'] = self.__round_floats(croppedBB)
|
412 |
+
resizedannot['area'] = self.__round_floats(croppedBB[2]*croppedBB[3])
|
413 |
+
resizedannList.append(resizedannot)
|
414 |
+
else:
|
415 |
+
# If BB is non-person add it to resized annotations list as it is
|
416 |
+
resizedannList.append(resizedannot)
|
417 |
+
|
418 |
+
resizedanotDict['annotations'] = resizedannList
|
419 |
+
print('Saving resized annotations to json file...')
|
420 |
+
|
421 |
+
# Save resized annotations in json file
|
422 |
+
resizedanotDict = json.dumps(resizedanotDict)
|
423 |
+
with open(resizedAnnotPath, 'w') as outfile:
|
424 |
+
outfile.write(resizedanotDict)
|
425 |
+
|
426 |
+
print(f'{resizedAnnotPath} saved.')
|
427 |
+
t2 = time.time()
|
428 |
+
print(f'Elapsed time: {t2-t1} seconds')
|
429 |
+
|
430 |
+
# Taken from : https://github.com/hasanirtiza/Pedestron/blob/master/tools/convert_datasets/pycococreatortools.py
|
431 |
+
def create_image_info(image_id, file_name, image_size,
|
432 |
+
date_captured=datetime.datetime.utcnow().isoformat(' '),
|
433 |
+
license_id=1, coco_url="", flickr_url=""):
|
434 |
+
|
435 |
+
image_info = {
|
436 |
+
"id": image_id,
|
437 |
+
"file_name": file_name,
|
438 |
+
"width": image_size[0],
|
439 |
+
"height": image_size[1],
|
440 |
+
"date_captured": date_captured,
|
441 |
+
"license": license_id,
|
442 |
+
"coco_url": coco_url,
|
443 |
+
"flickr_url": flickr_url
|
444 |
+
}
|
445 |
+
|
446 |
+
return image_info
|
447 |
+
|
448 |
+
# Taken from : https://github.com/hasanirtiza/Pedestron/blob/master/tools/convert_datasets/pycococreatortools.py
|
449 |
+
def create_annotation_info(annotation_id, image_id, category_info, bounding_box):
|
450 |
+
is_crowd = category_info['is_crowd']
|
451 |
+
|
452 |
+
annotation_info = {
|
453 |
+
"id": annotation_id,
|
454 |
+
"image_id": image_id,
|
455 |
+
"category_id": category_info["id"],
|
456 |
+
"iscrowd": is_crowd,
|
457 |
+
"bbox": bounding_box
|
458 |
+
}
|
459 |
+
|
460 |
+
return annotation_info
|
461 |
+
|
462 |
+
def convWidertoCOCO(annotFile, orgImageDir):
|
463 |
+
'''
|
464 |
+
Converts wider dataset annotations to COCO format.
|
465 |
+
Args:
|
466 |
+
annotFile: Original annotation file
|
467 |
+
orgImageDir: Original Images directory
|
468 |
+
'''
|
469 |
+
|
470 |
+
totalImgnum = 0
|
471 |
+
imgID = 0
|
472 |
+
annID = 0
|
473 |
+
|
474 |
+
imgList = []
|
475 |
+
annList = []
|
476 |
+
|
477 |
+
category_info= {}
|
478 |
+
category_info['is_crowd'] = False
|
479 |
+
category_info['id'] = 1
|
480 |
+
|
481 |
+
data ={}
|
482 |
+
|
483 |
+
data['info'] = {'description': 'Example Dataset', 'url': '', 'version': '0.1.0', 'year': 2022, 'contributor': 'ljp', 'date_created': '2019-07-18 06:56:33.567522'}
|
484 |
+
data['categories'] = [{'id': 1, 'name': 'person', 'supercategory': 'person'}]
|
485 |
+
data['licences'] = [{'id': 1, 'name': 'Attribution-NonCommercial-ShareAlike License', 'url': 'http://creativecommons.org/licenses/by-nc-sa/2.0/'}]
|
486 |
+
|
487 |
+
with open(annotFile) as f:
|
488 |
+
for _, annot_raw in enumerate(tqdm(f)):
|
489 |
+
imgID += 1
|
490 |
+
|
491 |
+
annot_raw = annot_raw.split()
|
492 |
+
imgName = annot_raw[:1][0]
|
493 |
+
|
494 |
+
totalImgnum +=1
|
495 |
+
imageFullPath = os.path.join(orgImageDir,imgName)
|
496 |
+
try:
|
497 |
+
curImg = Image.open(imageFullPath)
|
498 |
+
image_size = curImg.size
|
499 |
+
|
500 |
+
BBs_str = annot_raw[1:]
|
501 |
+
bb_raw = [int(bb) for bb in BBs_str]
|
502 |
+
|
503 |
+
imgInf = create_image_info(image_id = imgID, file_name = imgName, image_size =image_size,
|
504 |
+
date_captured=datetime.datetime.utcnow().isoformat(' '),
|
505 |
+
license_id=1, coco_url="", flickr_url="")
|
506 |
+
imgList.append(imgInf)
|
507 |
+
|
508 |
+
bb = []
|
509 |
+
for i, p in enumerate(bb_raw):
|
510 |
+
|
511 |
+
bb.append(p)
|
512 |
+
if ((i+1)%4 == 0):
|
513 |
+
annID += 1
|
514 |
+
ann = create_annotation_info(annID, imgID, category_info = category_info, bounding_box = bb)
|
515 |
+
annList.append(ann)
|
516 |
+
bb = []
|
517 |
+
|
518 |
+
except:
|
519 |
+
print(f'Cannot create annot for {imgName}, image does not exist in given directory.')
|
520 |
+
|
521 |
+
data['annotations'] = annList
|
522 |
+
data['images'] = imgList
|
523 |
+
|
524 |
+
|
525 |
+
cur_dir = os.getcwd()
|
526 |
+
processed_annot_path = os.path.join(cur_dir,'datasets','wider','annotations')
|
527 |
+
|
528 |
+
if not os.path.isdir(processed_annot_path):
|
529 |
+
os.makedirs(processed_annot_path)
|
530 |
+
|
531 |
+
orgCOCOAnnotFile = os.path.join( processed_annot_path ,'orig_annot.json')
|
532 |
+
|
533 |
+
with open(orgCOCOAnnotFile, 'w') as fp:
|
534 |
+
json.dump(data, fp)
|
535 |
+
|
536 |
+
|
537 |
+
print('Annotations saved as: ' + orgCOCOAnnotFile)
|
538 |
+
print(f'Created {annID} COCO annotations for total {totalImgnum} images')
|
539 |
+
print('')
|
540 |
+
return orgCOCOAnnotFile
|
541 |
+
|
542 |
+
|
543 |
+
def main():
|
544 |
+
parser = argparse.ArgumentParser(description='This script converts original Wider Person'
|
545 |
+
'Validation Dataset images to 512 x 512'
|
546 |
+
'Then resisez the annotations accordingly, saves new images and annotations under datasets folder')
|
547 |
+
parser.add_argument('-ip', '--wider_images_path', type=str, required = True,
|
548 |
+
help='path of the folder containing original images')
|
549 |
+
parser.add_argument('-af', '--wider_annotfile', type=str, required = True,
|
550 |
+
help='full path of original annotations file e.g. ./some/path/some_annot.json')
|
551 |
+
|
552 |
+
|
553 |
+
args = parser.parse_args()
|
554 |
+
wider_images_path = args.wider_images_path
|
555 |
+
wider_annotfile = args.wider_annotfile
|
556 |
+
|
557 |
+
# Prepare images
|
558 |
+
print('')
|
559 |
+
print('Prescaling and Center-cropping original images to 512 x 512')
|
560 |
+
preProcessImages(wider_images_path)
|
561 |
+
print('\n'*2)
|
562 |
+
|
563 |
+
# Convert original wider annotations in to COCO format
|
564 |
+
print('Converting original annotations to COCO format')
|
565 |
+
orgCOCOAnnotFile = convWidertoCOCO(wider_annotfile, wider_images_path)
|
566 |
+
print('\n'*2)
|
567 |
+
|
568 |
+
# Prescale/Center-crop annotations and save
|
569 |
+
print('Prescaling/Center-cropping original annotations in COCO format')
|
570 |
+
transform = transforms.Compose([transforms.CenterCrop(512), transforms.ToTensor()])
|
571 |
+
dataset = CocoDetection(root=wider_images_path, annFile=orgCOCOAnnotFile, transform=transform,scaleImgforCrop= 512)
|
572 |
+
targetFileName = 'instances_val.json'
|
573 |
+
dataset.createResizedAnnotJson(targetFileName=targetFileName)
|
574 |
+
os.remove(orgCOCOAnnotFile)
|
575 |
+
|
576 |
+
if __name__ == '__main__':
|
577 |
+
main()
|
experiments/demo.gif
ADDED
Git LFS Details
|
experiments/shallow800_mnv2ssdlite_8b_retrain_wider_optimizedAnchors_annealedlr_0_95/Histograms/histograms_fpt_cons_train_experiment/fpt_cons_train_bn_biaseses.jpg
ADDED
Git LFS Details
|
experiments/shallow800_mnv2ssdlite_8b_retrain_wider_optimizedAnchors_annealedlr_0_95/Histograms/histograms_fpt_cons_train_experiment/fpt_cons_train_bn_weights.jpg
ADDED
Git LFS Details
|
experiments/shallow800_mnv2ssdlite_8b_retrain_wider_optimizedAnchors_annealedlr_0_95/Histograms/histograms_fpt_cons_train_experiment/fpt_cons_train_layer_biaseses.jpg
ADDED
Git LFS Details
|
experiments/shallow800_mnv2ssdlite_8b_retrain_wider_optimizedAnchors_annealedlr_0_95/Histograms/histograms_fpt_cons_train_experiment/fpt_cons_train_layer_weights.jpg
ADDED
Git LFS Details
|
experiments/shallow800_mnv2ssdlite_8b_retrain_wider_optimizedAnchors_annealedlr_0_95/Histograms/histograms_original_experiment/original_bn_biaseses.jpg
ADDED
Git LFS Details
|
experiments/shallow800_mnv2ssdlite_8b_retrain_wider_optimizedAnchors_annealedlr_0_95/Histograms/histograms_original_experiment/original_bn_weights.jpg
ADDED
Git LFS Details
|
experiments/shallow800_mnv2ssdlite_8b_retrain_wider_optimizedAnchors_annealedlr_0_95/Histograms/histograms_original_experiment/original_layer_biaseses.jpg
ADDED
Git LFS Details
|
experiments/shallow800_mnv2ssdlite_8b_retrain_wider_optimizedAnchors_annealedlr_0_95/Histograms/histograms_original_experiment/original_layer_weights.jpg
ADDED
Git LFS Details
|
experiments/shallow800_mnv2ssdlite_8b_retrain_wider_optimizedAnchors_annealedlr_0_95/Histograms/histograms_qat_after_trained_experiment/qat_after_trained_bn_biaseses.jpg
ADDED
Git LFS Details
|
experiments/shallow800_mnv2ssdlite_8b_retrain_wider_optimizedAnchors_annealedlr_0_95/Histograms/histograms_qat_after_trained_experiment/qat_after_trained_bn_weights.jpg
ADDED
Git LFS Details
|
experiments/shallow800_mnv2ssdlite_8b_retrain_wider_optimizedAnchors_annealedlr_0_95/Histograms/histograms_qat_after_trained_experiment/qat_after_trained_layer_biaseses.jpg
ADDED
Git LFS Details
|
experiments/shallow800_mnv2ssdlite_8b_retrain_wider_optimizedAnchors_annealedlr_0_95/Histograms/histograms_qat_after_trained_experiment/qat_after_trained_layer_weights.jpg
ADDED
Git LFS Details
|
experiments/shallow800_mnv2ssdlite_8b_retrain_wider_optimizedAnchors_annealedlr_0_95/Histograms/histograms_qat_pre_trained_experiment/qat_pre_trained_bn_biaseses.jpg
ADDED
Git LFS Details
|
experiments/shallow800_mnv2ssdlite_8b_retrain_wider_optimizedAnchors_annealedlr_0_95/Histograms/histograms_qat_pre_trained_experiment/qat_pre_trained_bn_weights.jpg
ADDED
Git LFS Details
|
experiments/shallow800_mnv2ssdlite_8b_retrain_wider_optimizedAnchors_annealedlr_0_95/Histograms/histograms_qat_pre_trained_experiment/qat_pre_trained_layer_biaseses.jpg
ADDED
Git LFS Details
|
experiments/shallow800_mnv2ssdlite_8b_retrain_wider_optimizedAnchors_annealedlr_0_95/Histograms/histograms_qat_pre_trained_experiment/qat_pre_trained_layer_weights.jpg
ADDED
Git LFS Details
|
experiments/shallow800_mnv2ssdlite_8b_retrain_wider_optimizedAnchors_annealedlr_0_95/fpt_experiment.pth.tar
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:13b1b6622d7a390468d66c9629e562cf1f3dba0bf2d582aee64f5fc8c44eb20f
|
3 |
+
size 7807691
|
experiments/shallow800_mnv2ssdlite_8b_retrain_wider_optimizedAnchors_annealedlr_0_95/hardware_experiment.pth.tar
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:e4712fd8026f221b6a40f464438821858389a7a9d021da6c4f2ddb881d7a695e
|
3 |
+
size 7481103
|
experiments/shallow800_mnv2ssdlite_8b_retrain_wider_optimizedAnchors_annealedlr_0_95/training_experiment.pth.tar
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:79dbbd0f1849c213da61f71985dce57a88b7cd03881cd093a44b3daab61902f4
|
3 |
+
size 7480143
|
experiments/shallow830_mnv2ssdlite_2b8b_wider_somelayers_excluded_annealedlr_0_95/Histograms/histograms_fpt_cons_train_experiment/fpt_cons_train_bn_biaseses.jpg
ADDED
Git LFS Details
|
experiments/shallow830_mnv2ssdlite_2b8b_wider_somelayers_excluded_annealedlr_0_95/Histograms/histograms_fpt_cons_train_experiment/fpt_cons_train_bn_weights.jpg
ADDED
Git LFS Details
|
experiments/shallow830_mnv2ssdlite_2b8b_wider_somelayers_excluded_annealedlr_0_95/Histograms/histograms_fpt_cons_train_experiment/fpt_cons_train_layer_biaseses.jpg
ADDED
Git LFS Details
|
experiments/shallow830_mnv2ssdlite_2b8b_wider_somelayers_excluded_annealedlr_0_95/Histograms/histograms_fpt_cons_train_experiment/fpt_cons_train_layer_weights.jpg
ADDED
Git LFS Details
|
experiments/shallow830_mnv2ssdlite_2b8b_wider_somelayers_excluded_annealedlr_0_95/Histograms/histograms_original_experiment/original_bn_biaseses.jpg
ADDED
Git LFS Details
|
experiments/shallow830_mnv2ssdlite_2b8b_wider_somelayers_excluded_annealedlr_0_95/Histograms/histograms_original_experiment/original_bn_weights.jpg
ADDED
Git LFS Details
|
experiments/shallow830_mnv2ssdlite_2b8b_wider_somelayers_excluded_annealedlr_0_95/Histograms/histograms_original_experiment/original_layer_biaseses.jpg
ADDED
Git LFS Details
|
experiments/shallow830_mnv2ssdlite_2b8b_wider_somelayers_excluded_annealedlr_0_95/Histograms/histograms_original_experiment/original_layer_weights.jpg
ADDED
Git LFS Details
|
experiments/shallow830_mnv2ssdlite_2b8b_wider_somelayers_excluded_annealedlr_0_95/Histograms/histograms_qat_after_trained_experiment/qat_after_trained_bn_biaseses.jpg
ADDED
Git LFS Details
|
experiments/shallow830_mnv2ssdlite_2b8b_wider_somelayers_excluded_annealedlr_0_95/Histograms/histograms_qat_after_trained_experiment/qat_after_trained_bn_weights.jpg
ADDED
Git LFS Details
|
experiments/shallow830_mnv2ssdlite_2b8b_wider_somelayers_excluded_annealedlr_0_95/Histograms/histograms_qat_after_trained_experiment/qat_after_trained_layer_biaseses.jpg
ADDED
Git LFS Details
|
experiments/shallow830_mnv2ssdlite_2b8b_wider_somelayers_excluded_annealedlr_0_95/Histograms/histograms_qat_after_trained_experiment/qat_after_trained_layer_weights.jpg
ADDED
Git LFS Details
|
experiments/shallow830_mnv2ssdlite_2b8b_wider_somelayers_excluded_annealedlr_0_95/Histograms/histograms_qat_pre_trained_experiment/qat_pre_trained_bn_biaseses.jpg
ADDED
Git LFS Details
|
experiments/shallow830_mnv2ssdlite_2b8b_wider_somelayers_excluded_annealedlr_0_95/Histograms/histograms_qat_pre_trained_experiment/qat_pre_trained_bn_weights.jpg
ADDED
Git LFS Details
|
experiments/shallow830_mnv2ssdlite_2b8b_wider_somelayers_excluded_annealedlr_0_95/Histograms/histograms_qat_pre_trained_experiment/qat_pre_trained_layer_biaseses.jpg
ADDED
Git LFS Details
|
experiments/shallow830_mnv2ssdlite_2b8b_wider_somelayers_excluded_annealedlr_0_95/Histograms/histograms_qat_pre_trained_experiment/qat_pre_trained_layer_weights.jpg
ADDED
Git LFS Details
|
experiments/shallow830_mnv2ssdlite_2b8b_wider_somelayers_excluded_annealedlr_0_95/fpt_experiment.pth.tar
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:b6629e998ec6a9a6482aeaa386370e25b26b3fae0206d7073401581dbae708a9
|
3 |
+
size 5433449
|
experiments/shallow830_mnv2ssdlite_2b8b_wider_somelayers_excluded_annealedlr_0_95/hardware_experiment.pth.tar
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:5eb91a81fcd0442b75e893822ffa7602eddbe9a7002b8c8062522d87986720e5
|
3 |
+
size 5203607
|
experiments/shallow830_mnv2ssdlite_2b8b_wider_somelayers_excluded_annealedlr_0_95/modified_model.py
ADDED
@@ -0,0 +1,147 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
###########################################################################
|
2 |
+
# Computer vision - Embedded person tracking demo software by HyperbeeAI. #
|
3 |
+
# Copyrights © 2023 Hyperbee.AI Inc. All rights reserved. main@shallow.ai #
|
4 |
+
###########################################################################
|
5 |
+
import torch.nn as nn
|
6 |
+
import qat_core.layers as layers
|
7 |
+
|
8 |
+
class mnv2_SSDlite(nn.Module):
|
9 |
+
def __init__(self, in_channels=3, n_classes=1):
|
10 |
+
super(mnv2_SSDlite, self).__init__()
|
11 |
+
|
12 |
+
self.conv1 = layers.conv(C_in_channels=in_channels, D_out_channels=32, K_kernel_dimension=3, stride=2, padding=(1,1,1,1), batchnorm=True, batchnorm_affine=True, bias=False, activation='relu', quantization_mode = 'fpt_unconstrained')
|
13 |
+
|
14 |
+
self.epw_conv2 = layers.conv(C_in_channels=32, D_out_channels=32, K_kernel_dimension=1, stride=1, padding=(0,0,0,0), batchnorm=True, batchnorm_affine=True, bias=False, activation='relu', quantization_mode = 'fpt_unconstrained')
|
15 |
+
self.dw_conv2 = layers.conv(C_in_channels=32, D_out_channels=32, K_kernel_dimension=3, stride=1, padding=(1,1,1,1), batchnorm=True, batchnorm_affine=True, bias=False, activation='relu', num_groups=32, quantization_mode = 'fpt_unconstrained')
|
16 |
+
self.ppw_conv2 = layers.conv(C_in_channels=32, D_out_channels=16, K_kernel_dimension=1, stride=1, padding=(0,0,0,0), batchnorm=True, batchnorm_affine=True, bias=False, quantization_mode = 'fpt_unconstrained')
|
17 |
+
|
18 |
+
self.epw_conv3 = layers.conv(C_in_channels=16, D_out_channels=96, K_kernel_dimension=1, stride=1, padding=(0,0,0,0), batchnorm=True, batchnorm_affine=True, bias=False, activation='relu', quantization_mode = 'fpt_unconstrained')
|
19 |
+
self.dw_conv3 = layers.conv(C_in_channels=96, D_out_channels=96, K_kernel_dimension=3, stride=2, padding=(1,1,1,1), batchnorm=True, batchnorm_affine=True, bias=False, activation='relu', num_groups=96, quantization_mode = 'fpt_unconstrained')
|
20 |
+
self.ppw_conv3 = layers.conv(C_in_channels=96, D_out_channels=24, K_kernel_dimension=1, stride=1, padding=(0,0,0,0), batchnorm=True, batchnorm_affine=True, bias=False, quantization_mode = 'fpt_unconstrained')
|
21 |
+
self.epw_conv4 = layers.conv(C_in_channels=24, D_out_channels=144, K_kernel_dimension=1, stride=1, padding=(0,0,0,0), batchnorm=True, batchnorm_affine=True, bias=False, activation='relu', quantization_mode = 'fpt_unconstrained')
|
22 |
+
self.dw_conv4 = layers.conv(C_in_channels=144, D_out_channels=144, K_kernel_dimension=3, stride=1, padding=(1,1,1,1), batchnorm=True, batchnorm_affine=True, bias=False, activation='relu', num_groups=144, quantization_mode = 'fpt_unconstrained')
|
23 |
+
self.ppw_conv4 = layers.conv(C_in_channels=144, D_out_channels=24, K_kernel_dimension=1, stride=1, padding=(0,0,0,0), batchnorm=True, batchnorm_affine=True, bias=False, quantization_mode = 'fpt_unconstrained')
|
24 |
+
|
25 |
+
self.epw_conv5 = layers.conv(C_in_channels=24, D_out_channels=144, K_kernel_dimension=1, stride=1, padding=(0,0,0,0), batchnorm=True, batchnorm_affine=True, bias=False, activation='relu', quantization_mode = 'fpt_unconstrained')
|
26 |
+
self.dw_conv5 = layers.conv(C_in_channels=144, D_out_channels=144, K_kernel_dimension=3, stride=2, padding=(1,1,1,1), batchnorm=True, batchnorm_affine=True, bias=False, activation='relu', num_groups=144, quantization_mode = 'fpt_unconstrained')
|
27 |
+
self.ppw_conv5 = layers.conv(C_in_channels=144, D_out_channels=32, K_kernel_dimension=1, stride=1, padding=(0,0,0,0), batchnorm=True, batchnorm_affine=True, bias=False, quantization_mode = 'fpt_unconstrained')
|
28 |
+
|
29 |
+
self.epw_conv7 = layers.conv(C_in_channels=32, D_out_channels=192, K_kernel_dimension=1, stride=1, padding=(0,0,0,0), batchnorm=True, batchnorm_affine=True, bias=False, activation='relu', quantization_mode = 'fpt_unconstrained')
|
30 |
+
self.dw_conv7 = layers.conv(C_in_channels=192, D_out_channels=192, K_kernel_dimension=3, stride=1, padding=(1,1,1,1), batchnorm=True, batchnorm_affine=True, bias=False, activation='relu', num_groups=192, quantization_mode = 'fpt_unconstrained')
|
31 |
+
self.ppw_conv7 = layers.conv(C_in_channels=192, D_out_channels=32, K_kernel_dimension=1, stride=1, padding=(0,0,0,0), batchnorm=True, batchnorm_affine=True, bias=False, quantization_mode = 'fpt_unconstrained')
|
32 |
+
|
33 |
+
self.epw_conv8 = layers.conv(C_in_channels=32, D_out_channels=192, K_kernel_dimension=1, stride=1, padding=(0,0,0,0), batchnorm=True, batchnorm_affine=True, bias=False, activation='relu', quantization_mode = 'fpt_unconstrained')
|
34 |
+
self.dw_conv8 = layers.conv(C_in_channels=192, D_out_channels=192, K_kernel_dimension=3, stride=2, padding=(1,1,1,1), batchnorm=True, batchnorm_affine=True, bias=False, activation='relu', num_groups=192, quantization_mode = 'fpt_unconstrained')
|
35 |
+
self.ppw_conv8 = layers.conv(C_in_channels=192, D_out_channels=64, K_kernel_dimension=1, stride=1, padding=(0,0,0,0), batchnorm=True, batchnorm_affine=True, bias=False, quantization_mode = 'fpt_unconstrained')
|
36 |
+
|
37 |
+
self.epw_conv11 = layers.conv(C_in_channels=64, D_out_channels=384, K_kernel_dimension=1, stride=1, padding=(0,0,0,0), batchnorm=True, batchnorm_affine=True, bias=False, activation='relu', quantization_mode = 'fpt_unconstrained')
|
38 |
+
self.dw_conv11 = layers.conv(C_in_channels=384, D_out_channels=384, K_kernel_dimension=3, stride=1, padding=(1,1,1,1), batchnorm=True, batchnorm_affine=True, bias=False, activation='relu', num_groups=384, quantization_mode = 'fpt_unconstrained')
|
39 |
+
self.ppw_conv11 = layers.conv(C_in_channels=384, D_out_channels=64, K_kernel_dimension=1, stride=1, padding=(0,0,0,0), batchnorm=True, batchnorm_affine=True, bias=False, quantization_mode = 'fpt_unconstrained')
|
40 |
+
|
41 |
+
self.epw_conv12 = layers.conv(C_in_channels=64, D_out_channels=384, K_kernel_dimension=1, stride=1, padding=(0,0,0,0), batchnorm=True, batchnorm_affine=True, bias=False, activation='relu', quantization_mode = 'fpt_unconstrained')
|
42 |
+
self.dw_conv12 = layers.conv(C_in_channels=384, D_out_channels=384, K_kernel_dimension=3, stride=1, padding=(1,1,1,1), batchnorm=True, batchnorm_affine=True, bias=False, activation='relu', num_groups=384, quantization_mode = 'fpt_unconstrained')
|
43 |
+
self.ppw_conv12 = layers.conv(C_in_channels=384, D_out_channels=96, K_kernel_dimension=1, stride=1, padding=(0,0,0,0), batchnorm=True, batchnorm_affine=True, bias=False, quantization_mode = 'fpt_unconstrained')
|
44 |
+
|
45 |
+
self.epw_conv14 = layers.conv(C_in_channels=96, D_out_channels=576, K_kernel_dimension=1, stride=1, padding=(0,0,0,0), batchnorm=True, batchnorm_affine=True, bias=False, activation='relu', quantization_mode = 'fpt_unconstrained')
|
46 |
+
self.dw_conv14 = layers.conv(C_in_channels=576, D_out_channels=576, K_kernel_dimension=3, stride=1, padding=(1,1,1,1), batchnorm=True, batchnorm_affine=True, bias=False, activation='relu', num_groups=576, quantization_mode = 'fpt_unconstrained')
|
47 |
+
self.ppw_conv14 = layers.conv(C_in_channels=576, D_out_channels=96, K_kernel_dimension=1, stride=1, padding=(0,0,0,0), batchnorm=True, batchnorm_affine=True, bias=False, quantization_mode = 'fpt_unconstrained') #ilk çıkış: torch.Size([2, 96, /16, /16])
|
48 |
+
|
49 |
+
self.epw_conv15 = layers.conv(C_in_channels=96, D_out_channels=576, K_kernel_dimension=1, stride=1, padding=(0,0,0,0), batchnorm=True, batchnorm_affine=True, bias=False, activation='relu', quantization_mode = 'fpt_unconstrained')
|
50 |
+
self.dw_conv15 = layers.conv(C_in_channels=576, D_out_channels=576, K_kernel_dimension=3, stride=2, padding=(1,1,1,1), batchnorm=True, batchnorm_affine=True, bias=False, activation='relu', num_groups=576, quantization_mode = 'fpt_unconstrained')
|
51 |
+
self.ppw_conv15 = layers.conv(C_in_channels=576, D_out_channels=160, K_kernel_dimension=1, stride=1, padding=(0,0,0,0), batchnorm=True, batchnorm_affine=True, bias=False, quantization_mode = 'fpt_unconstrained')
|
52 |
+
|
53 |
+
self.epw_conv17 = layers.conv(C_in_channels=160, D_out_channels=960, K_kernel_dimension=1, stride=1, padding=(0,0,0,0), batchnorm=True, batchnorm_affine=True, bias=False, activation='relu', quantization_mode = 'fpt_unconstrained')
|
54 |
+
self.dw_conv17 = layers.conv(C_in_channels=960, D_out_channels=960, K_kernel_dimension=3, stride=1, padding=(1,1,1,1), batchnorm=True, batchnorm_affine=True, bias=False, activation='relu', num_groups=960, quantization_mode = 'fpt_unconstrained')
|
55 |
+
self.ppw_conv17 = layers.conv(C_in_channels=960, D_out_channels=160, K_kernel_dimension=1, stride=1, padding=(0,0,0,0), batchnorm=True, batchnorm_affine=True, bias=False, quantization_mode = 'fpt_unconstrained')
|
56 |
+
|
57 |
+
self.epw_conv18 = layers.conv(C_in_channels=160, D_out_channels=960, K_kernel_dimension=1, stride=1, padding=(0,0,0,0), batchnorm=True, batchnorm_affine=True, bias=False, activation='relu', quantization_mode = 'fpt_unconstrained')
|
58 |
+
self.dw_conv18 = layers.conv(C_in_channels=960, D_out_channels=960, K_kernel_dimension=3, stride=1, padding=(1,1,1,1), batchnorm=True, batchnorm_affine=True, bias=False, activation='relu', num_groups=960, quantization_mode = 'fpt_unconstrained')
|
59 |
+
self.ppw_conv18 = layers.conv(C_in_channels=960, D_out_channels=320, K_kernel_dimension=1, stride=1, padding=(0,0,0,0), batchnorm=True, batchnorm_affine=True, bias=False, quantization_mode = 'fpt_unconstrained') #ikinci çıkış: torch.Size([2, 320, /32, /32])
|
60 |
+
|
61 |
+
self.head1_dw_classification = layers.conv(C_in_channels=96, D_out_channels=96, K_kernel_dimension=3, stride=1, padding=(1,1,1,1), batchnorm=True, batchnorm_affine=True, activation='relu', num_groups=96, quantization_mode = 'fpt_unconstrained')
|
62 |
+
self.head1_pw_classification = layers.conv(C_in_channels=96, D_out_channels=8, K_kernel_dimension=1, stride=1, padding=(0,0,0,0), output_width_30b = True, quantization_mode = 'fpt_unconstrained')
|
63 |
+
self.head1_dw_regression = layers.conv(C_in_channels=96, D_out_channels=96, K_kernel_dimension=3, stride=1, padding=(1,1,1,1), batchnorm=True, batchnorm_affine=True, activation='relu', num_groups=96, quantization_mode = 'fpt_unconstrained')
|
64 |
+
self.head1_pw_regression = layers.conv(C_in_channels=96, D_out_channels=16, K_kernel_dimension=1, stride=1, padding=(0,0,0,0), output_width_30b = True, quantization_mode = 'fpt_unconstrained')
|
65 |
+
|
66 |
+
self.head2_dw_classification = layers.conv(C_in_channels=320, D_out_channels=320, K_kernel_dimension=3, stride=1, padding=(1,1,1,1), batchnorm=True, batchnorm_affine=True, activation='relu', num_groups=320, quantization_mode = 'fpt_unconstrained')
|
67 |
+
self.head2_pw_classification = layers.conv(C_in_channels=320, D_out_channels=10, K_kernel_dimension=1, stride=1, padding=(0,0,0,0), output_width_30b = True, quantization_mode = 'fpt_unconstrained')
|
68 |
+
self.head2_dw_regression = layers.conv(C_in_channels=320, D_out_channels=320, K_kernel_dimension=3, stride=1, padding=(1,1,1,1), batchnorm=True, batchnorm_affine=True, activation='relu', num_groups=320, quantization_mode = 'fpt_unconstrained')
|
69 |
+
self.head2_pw_regression = layers.conv(C_in_channels=320, D_out_channels=20, K_kernel_dimension=1, stride=1, padding=(0,0,0,0), output_width_30b = True, quantization_mode = 'fpt_unconstrained')
|
70 |
+
|
71 |
+
self.add_residual = layers.add_residual(quantization_mode = 'fpt_unconstrained')
|
72 |
+
|
73 |
+
|
74 |
+
def forward(self, x):
|
75 |
+
x = self.conv1(x)
|
76 |
+
|
77 |
+
x = self.epw_conv2(x)
|
78 |
+
x = self.dw_conv2(x)
|
79 |
+
x = self.ppw_conv2(x)
|
80 |
+
|
81 |
+
x = self.epw_conv3(x)
|
82 |
+
x = self.dw_conv3(x)
|
83 |
+
x = self.ppw_conv3(x)
|
84 |
+
res4 = x
|
85 |
+
x = self.epw_conv4(x)
|
86 |
+
x = self.dw_conv4(x)
|
87 |
+
x = self.ppw_conv4(x)
|
88 |
+
x = self.add_residual(x,res4)
|
89 |
+
|
90 |
+
x = self.epw_conv5(x)
|
91 |
+
x = self.dw_conv5(x)
|
92 |
+
x = self.ppw_conv5(x)
|
93 |
+
|
94 |
+
res7 = x
|
95 |
+
x = self.epw_conv7(x)
|
96 |
+
x = self.dw_conv7(x)
|
97 |
+
x = self.ppw_conv7(x)
|
98 |
+
x = self.add_residual(x,res7)
|
99 |
+
|
100 |
+
x = self.epw_conv8(x)
|
101 |
+
x = self.dw_conv8(x)
|
102 |
+
x = self.ppw_conv8(x)
|
103 |
+
|
104 |
+
res11 = x
|
105 |
+
x = self.epw_conv11(x)
|
106 |
+
x = self.dw_conv11(x)
|
107 |
+
x = self.ppw_conv11(x)
|
108 |
+
x = self.add_residual(x,res11)
|
109 |
+
|
110 |
+
x = self.epw_conv12(x)
|
111 |
+
x = self.dw_conv12(x)
|
112 |
+
x = self.ppw_conv12(x)
|
113 |
+
|
114 |
+
res14 = x
|
115 |
+
x = self.epw_conv14(x)
|
116 |
+
x = self.dw_conv14(x)
|
117 |
+
x = self.ppw_conv14(x)
|
118 |
+
x = self.add_residual(x,res14)
|
119 |
+
output1 = x
|
120 |
+
|
121 |
+
x = self.epw_conv15(x)
|
122 |
+
x = self.dw_conv15(x)
|
123 |
+
x = self.ppw_conv15(x)
|
124 |
+
|
125 |
+
res17 = x
|
126 |
+
x = self.epw_conv17(x)
|
127 |
+
x = self.dw_conv17(x)
|
128 |
+
x = self.ppw_conv17(x)
|
129 |
+
x = self.add_residual(x,res17)
|
130 |
+
|
131 |
+
x = self.epw_conv18(x)
|
132 |
+
x = self.dw_conv18(x)
|
133 |
+
x = self.ppw_conv18(x)
|
134 |
+
output2 = x
|
135 |
+
|
136 |
+
output1_class = self.head1_dw_classification(output1)
|
137 |
+
output1_class = self.head1_pw_classification(output1_class)
|
138 |
+
output1_reg = self.head1_dw_regression(output1)
|
139 |
+
output1_reg = self.head1_pw_regression(output1_reg)
|
140 |
+
|
141 |
+
output2_class = self.head2_dw_classification(output2)
|
142 |
+
output2_class = self.head2_pw_classification(output2_class)
|
143 |
+
output2_reg = self.head2_dw_regression(output2)
|
144 |
+
output2_reg = self.head2_pw_regression(output2_reg)
|
145 |
+
|
146 |
+
#print(f"Output1 Regression: {output1_reg.shape}, Output1 Classification: {output1_class.shape}\nOutput2 Regression: {output2_reg.shape}, Output2 Classification: {output2_class.shape}")
|
147 |
+
return (output1_reg, output1_class, output2_reg, output2_class)
|
experiments/shallow830_mnv2ssdlite_2b8b_wider_somelayers_excluded_annealedlr_0_95/training_experiment.pth.tar
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:24f990cf40e986094eb4695dfd3b310ff358ffffaa50ff755a8ab71b5f3e9fde
|
3 |
+
size 5202903
|