├── .gitattributes
├── LICENSE
├── README.md
├── animalweb_preprocessing.ipynb
├── animefaces_preprocessing.ipynb
├── anyface_detections.png
├── artisticfaces_preprocessing.ipynb
├── birds_processing.ipynb
├── data2yolo.ipynb
├── dataset
└── .gitignore
├── external_selection.ipynb
├── icartoon_preprocessing.ipynb
├── metfaces_preprocessing.ipynb
├── original-external
└── .gitignore
├── pets_preprocessing.ipynb
├── requirements.txt
├── selected-external
├── animefaces.txt
├── artisticfaces.txt
├── birds.txt
├── metfaces.txt
├── pets.txt
├── tj.txt
└── turtles.txt
├── split_indoor_outdoor.ipynb
├── test_images
└── .gitignore
├── test_videos
└── .gitignore
├── tfw_preprocessing.ipynb
├── tj_preprocessing.ipynb
├── turtles_preprocessing.ipynb
├── widerface_preprocessing.ipynb
└── yolov5-face
├── LICENSE
├── data
├── agnostic.yaml
├── argoverse_hd.yaml
├── coco.yaml
├── coco128.yaml
├── hyp.finetune.yaml
├── hyp.scratch.yaml
├── hyp_1.yaml
├── retinaface2yolo.py
├── scripts
│ ├── get_argoverse_hd.sh
│ ├── get_coco.sh
│ └── get_voc.sh
├── train2yolo.py
├── val2yolo.py
├── voc.yaml
└── widerface.yaml
├── detect_face.py
├── evaluate-external.ipynb
├── evaluate-selected-external.ipynb
├── evaluate-test-images.ipynb
├── evaluate-test-videos.ipynb
├── evaluate-widerface.ipynb
├── evaluate.ipynb
├── export.py
├── hubconf.py
├── models
├── __init__.py
├── blazeface.yaml
├── blazeface_fpn.yaml
├── common.py
├── experimental.py
├── yolo.py
├── yolov5l.yaml
├── yolov5l6.yaml
├── yolov5m.yaml
├── yolov5m6.yaml
├── yolov5n-0.5.yaml
├── yolov5n.yaml
├── yolov5n6.yaml
├── yolov5s.yaml
└── yolov5s6.yaml
├── test.py
├── test_widerface.py
├── torch2trt
├── imgs
│ ├── yolov5l-face.jpg
│ ├── yolov5m-face.jpg
│ ├── yolov5n-0.5.jpg
│ ├── yolov5n-face.jpg
│ └── yolov5s-face.jpg
├── main.py
├── readme.md
├── readme_CN.md
├── sample.jpg
├── speed.py
└── trt_model.py
├── train.py
├── utils
├── __init__.py
├── activations.py
├── autoanchor.py
├── aws
│ ├── __init__.py
│ ├── mime.sh
│ ├── resume.py
│ └── userdata.sh
├── datasets.py
├── face_datasets.py
├── general.py
├── google_app_engine
│ ├── Dockerfile
│ ├── additional_requirements.txt
│ └── app.yaml
├── google_utils.py
├── infer_utils.py
├── loss.py
├── metrics.py
├── plots.py
├── torch_utils.py
└── wandb_logging
│ ├── __init__.py
│ ├── __pycache__
│ ├── __init__.cpython-38.pyc
│ └── wandb_utils.cpython-38.pyc
│ ├── log_dataset.py
│ └── wandb_utils.py
├── weights
└── download_weights.sh
├── widerface
├── test
│ ├── label.txt
│ └── wider_test.txt
├── train
│ └── label.txt
└── val
│ ├── label.txt
│ └── wider_val.txt
└── widerface_evaluate
├── README.md
├── bbox.cpython-37m-x86_64-linux-gnu.so
├── bbox.cpython-38-x86_64-linux-gnu.so
├── box_overlaps.c
├── box_overlaps.pyx
├── build
├── temp.linux-x86_64-3.7
│ └── box_overlaps.o
└── temp.linux-x86_64-3.8
│ └── box_overlaps.o
├── evaluation.py
├── ground_truth
├── wider_easy_val.mat
├── wider_face_val.mat
├── wider_hard_val.mat
└── wider_medium_val.mat
└── setup.py
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 ISSAI
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # README
2 |
3 | # AnyFace: A Data-Centric Approach For Input-Agnostic Face Detection
4 |
5 |
6 | ## Paper: [AnyFace: A Data-Centric Approach For Input-Agnostic Face Detection](https://ieeexplore.ieee.org/document/10066796)
7 |
8 |
9 | ## Online Demo Page https://issai.nu.edu.kz/anyface/
10 |
11 | ## Installation requirements
12 |
13 | Clone the repository and install all necessary packages:
14 |
15 | ```bash
16 | git clone https://github.com/IS2AI/AnyFace.git
17 | cd AnyFace
18 | pip install -r requirements.txt
19 | ```
20 |
21 | ## Datasets
22 |
23 | ### The following datasets were used to train, validate, and test the models
24 |
25 | Download them from the following links and rename their folders accordingly.
26 |
27 | | Dataset | Link | Folder Name |
28 | | --- | --- | --- |
29 | | Wider Face | http://shuoyang1213.me/WIDERFACE/ | widerface |
30 | | AnimalWeb | https://fdmaproject.wordpress.com/author/fdmaproject/ | animalweb |
31 | | iCartoonFace | https://github.com/luxiangju-PersonAI/iCartoonFace#dataset | icartoon |
32 | | TFW | https://github.com/IS2AI/TFW#downloading-the-dataset | tfw |
33 |
34 | ### Additional datasets
35 |
36 | The following datasets were used to test the best model in addition to the test set of the main dataset. You should download them from the following links into the `original-external/` directory. Then, rename the folders as shown in the table.
37 |
38 | | Dataset | Link | Folder Name |
39 | | --- | --- | --- |
40 | | Oxford-IIIT Pet Dataset | https://www.robots.ox.ac.uk/vgg/data/pets/ | pets |
41 | | CUB-200-2011 | https://www.kaggle.com/datasets/veeralakrishna/200-bird-species-with-11788-images | birds |
42 | | Artistic-Faces| https://faculty.runi.ac.il/arik/site/foa/artistic-faces-dataset.asp | artisticfaces |
43 | | MetFaces | https://github.com/NVlabs/metfaces-dataset | metfaces |
44 | | Sea Turtle Faces | https://www.kaggle.com/datasets/smaranjitghose/sea-turtle-face-detection | turtles |
45 | | Anime-Face-Detector | https://github.com/qhgz2013/anime-face-detector | animefaces |
46 | | Tom & Jerry's Faces | https://www.kaggle.com/datasets/boltuzamaki/tom-and-jerrys-face-detection-dateset | tj |
47 | | Labeled Fishes in the Wild Dataset | https://swfscdata.nmfs.noaa.gov/labeled-fishes-in-the-wild/ | fishes |
48 |
49 | ## Preprocessing Step
50 |
51 | Use notebooks in the main directory to pre-process the corresponding datasets.
52 |
53 | The preprocessed datasets are saved in `dataset/` directory. For each dataset, images are stored in `dataset//images/` and the corresponding labels are stored in `dataset/dataset_name/labels/` and in `dataset//labels_eval/`. Labels are saved in `.txt` files, where each `.txt` file has the same filename as corresponding image. Two labeling formats are used:
54 |
55 | Annotations in `dataset//labels/` follow the format used for training YOLOv5Face models:
56 | - `face x_center y_center width height x1 y1 x2 y2 x3 y3 x4 y4 x5 y5`
57 | - `x1,y1,...,x5,y5` correspond to the coordinates of the left eye, right eye, nose top, left mouth corner, and right mouth corner
58 | - all coordinates are normalized to values [0-1]
59 | - for faces without annotated landmarks, -1 is used instead of coordinates
60 |
61 | Annotations in `dataset/dataset_name/labels_eval/` follow the format used for [Object-Detection-Metrics](https://github.com/rafaelpadilla/Object-Detection-Metrics#create-the-ground-truth-files):
62 |
63 | - each row contains labels of one face
64 | - the format: `face x_left y_top width height`
65 | - the coordinates are NOT normalized.
66 |
67 | To make a random selection of 160 images from each external dataset, run the cells in [external_selection.ipynb](external_selection.ipynb). Selected images for each dataset are in `selected-external//` directory.
68 |
69 | ## Training Step
70 |
71 | Run the following command to train the YOLOv5Face model on WIDER Face, AnimalWeb, iCartoonFace and TFW datasets. The paths to these datasets are specified in the [yolov5-face/data/agnostic.yaml](yolov5-face/data/agnostic.yaml) file. The model type is selected by `--cfg models/yolov5l6.yaml`. The weights are randomly initialized `--weights ''`. However, pre-trained weights can be also used by providing an appropriate path. We used default hyperparameters inside [yolov5-face/data/hyp.scratch.yaml](yolov5-face/data/hyp.scratch.yaml). They can be changed by providing a path to `--hyp` argument. The full list of arguments is in [yolov5-face/train.py](yolov5-face/train.py).
72 |
73 | ```bash
74 | cd yolov5-face
75 | CUDA_VISIBLE_DEVICES="0,1" python train.py --data data/agnostic.yaml --cfg models/yolov5l6.yaml --weights '' --workers 32 --name 'exp1' --batch-size 128 --epochs 350
76 | ```
77 |
78 | The trained model is saved in `yolov5-face/runs/train//weights/` directory.
79 |
80 | For more information about training details, please refer to the [YOLOv5](https://github.com/ultralytics/yolov5) and [YOLOv5-face](https://github.com/deepcam-cn/yolov5-face) repository.
81 |
82 | ## Testing Step
83 |
84 | To get the predictions on the validation and test sets of the main datasets, run the [yolov5-face/evaluate.ipynb](yolov5-face/evaluate.ipynb) notebook. For the external datasets, use [yolov5-face/evaluate-external.ipynb](yolov5-face/evaluate-external.ipynb). These notebooks create detection .txt files in Object-Detection-Metrics format: `face confidence_score x_left y_top width height`. (The coordinates are not normalized)
85 |
86 | The detections are organized as follows:
87 |
88 | ```
89 | yolov5-face
90 | └─── Object-Detection-Metrics
91 | │ └─── results
92 | │ │ └─── val
93 | │ │ └─── test
94 | │ │ └─── external
95 | │ │ │ └───
96 | │ │ │ │ └───
97 | │ │ │ │ │ └─── detections_{IoU}_{conf}
98 | │ │ │ │ │ │ └─── .txt
99 | ```
100 |
101 | To compute average precision, precision, and recall for each dataset, use the [results.ipynb](yolov5-face/Object-Detection-Metrics/results.ipynb) and [results-external.ipynb](yolov5-face/Object-Detection-Metrics/results-external.ipynb) notebooks in the Object-Detection-Metrics directory.
102 |
103 | For the WIDER Face dataset, use [yolov5-face/evaluate-widerface.ipynb](yolov5-face/evaluate-widerface.ipynb) that stores the predictions in WIDER Face submission format:
104 |
105 | ```
106 | < image name >
107 | < number of faces in this image >
108 | < x_left y_top width height >
109 | ```
110 |
111 | Please note that for the evaluation, the dataset images need to be copied to corresponding`yolov5-face/widerface//images` directory.
112 |
113 | Then, use a matlab script from the website of WIDER Face to compute average precisions for the validation set. For more information refer to the WIDER Face dataset website. For more information refer to the [WIDER Face dataset](http://shuoyang1213.me/WIDERFACE/) website.
114 |
115 | To evaluate the model on the external datasets, [yolov5-face/evaluate-selected-external.ipynb](yolov5-face/evaluate-selected-external.ipynb) notebook saves the selected images with drawn predicted bounding boxes and confidence scores. The predictions are saved in `yolov5-face/selected-external-results/`.
116 |
117 | A similar notebook is provided for arbitrary test images. The predictions are saved in `yolov5-face/test-images-results`. We also provide [yolov5-face/evaluate-test-videos.ipynb](yolov5-face/evaluate-test-videos.ipynb) which extracts frames from the input video, makes predictions on the frames and constructs video back with bounding boxes. Testing images and testing videos should be put into `/test_images/` and `/test_videos/` in the main directory.
118 |
119 | ### Augmentation
120 |
121 | Please note that we utilize augmentation procedure at the inference to get better results. Thus, you can find `augment` argument in evaluation code. By default, augmentation is not performed when the argument is not specified or `None`. `augment=1` sets `s = [1, 0.83, 0.67]` for scaling and `f = [None, 3, None]` for flipping, where 3 is horizontal flipping. `augment=2` sets `s = [1, 0.83, 0.67, 1, 0.83, 0.67]` for scaling and `f = [None, None, None, 3, 3, 3]` for flipping, meaning that for all three image scales we infer both original and flipped image. To change these parameters refer to [yolov5-face/models/yolo.py](yolov5-face/models/yolo.py).
122 |
123 | ### Feature Visualization
124 |
125 | To visualize CNN layers of the model for a given input image, you can use `feature_vis` parameter in [yolov5-face/evaluate-selected-external.ipynb](yolov5-face/evaluate-selected-external.ipynb). By default feature maps of the C3 block are visualized. This can be changed in [yolov5-face/models/yolo.py](yolov5-face/models/yolo.py). Feature maps are saved to `yolov5-face/feature_visualization/`.
126 |
127 | ## Inference
128 |
129 | Download the most accurate model, YOLOv5l6, from [Google Drive](https://drive.google.com/file/d/1PuITYKZbpo6fFMX6mExN-sq_z54iWyDJ/view?usp=share_link) and save it in `yolov5-face/weights` directory. Then, run `yolov5-face/detect_face.py` to detect faces and facial landmarks on an image by providing image size, the path to weights and image.
130 |
131 | ```bash
132 | python detect_face.py --weights weights/yolov5l6_best.pt --source image_path --img-size 800
133 | ```
134 |
135 | ## In case of using our work in your research, please cite this paper
136 | ```
137 | @INPROCEEDINGS{10066796,
138 | author={Kuzdeuov, Askat and Koishigarina, Darina and Varol, Huseyin Atakan},
139 | booktitle={2023 IEEE International Conference on Big Data and Smart Computing (BigComp)},
140 | title={AnyFace: A Data-Centric Approach For Input-Agnostic Face Detection},
141 | year={2023},
142 | volume={},
143 | number={},
144 | pages={211-218},
145 | doi={10.1109/BigComp57234.2023.00042}}
146 | ```
147 |
148 | ## References
149 |
150 | [https://github.com/deepcam-cn/yolov5-face](https://github.com/deepcam-cn/yolov5-face)
151 |
152 | [https://github.com/rafaelpadilla/Object-Detection-Metrics](https://github.com/rafaelpadilla/Object-Detection-Metrics)
153 |
--------------------------------------------------------------------------------
/anyface_detections.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IS2AI/AnyFace/bed844d23be03334f7fc12b2c4fb3ba2ac530bab/anyface_detections.png
--------------------------------------------------------------------------------
/data2yolo.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": 21,
6 | "metadata": {},
7 | "outputs": [],
8 | "source": [
9 | "# import the necessary packages\n",
10 | "from imutils import paths\n",
11 | "import cv2\n",
12 | "import os"
13 | ]
14 | },
15 | {
16 | "cell_type": "code",
17 | "execution_count": 22,
18 | "metadata": {},
19 | "outputs": [],
20 | "source": [
21 | "def make_dir(dirName):\n",
22 | " # Create a target directory & all intermediate \n",
23 | " # directories if they don't exists\n",
24 | " if not os.path.exists(dirName):\n",
25 | " os.makedirs(dirName, exist_ok = True)\n",
26 | " print(\"[INFO] Directory \" , dirName , \" created\")\n",
27 | " else:\n",
28 | " print(\"[INFO] Directory \" , dirName , \" already exists\")"
29 | ]
30 | },
31 | {
32 | "cell_type": "code",
33 | "execution_count": 23,
34 | "metadata": {},
35 | "outputs": [
36 | {
37 | "data": {
38 | "text/plain": [
39 | "4"
40 | ]
41 | },
42 | "execution_count": 23,
43 | "metadata": {},
44 | "output_type": "execute_result"
45 | }
46 | ],
47 | "source": [
48 | "DATASET_PATH = 'dataset'\n",
49 | "\n",
50 | "dirs = os.listdir(DATASET_PATH)\n",
51 | "\n",
52 | "len(dirs)"
53 | ]
54 | },
55 | {
56 | "cell_type": "code",
57 | "execution_count": 24,
58 | "metadata": {},
59 | "outputs": [
60 | {
61 | "data": {
62 | "text/plain": [
63 | "['icartoon', 'animalweb', 'tfw', 'widerface']"
64 | ]
65 | },
66 | "execution_count": 24,
67 | "metadata": {},
68 | "output_type": "execute_result"
69 | }
70 | ],
71 | "source": [
72 | "dirs"
73 | ]
74 | },
75 | {
76 | "cell_type": "code",
77 | "execution_count": 25,
78 | "metadata": {},
79 | "outputs": [
80 | {
81 | "name": "stdout",
82 | "output_type": "stream",
83 | "text": [
84 | "[INFO] Directory dataset/icartoon/train/labels_yolo already exists\n",
85 | "[INFO] Directory dataset/icartoon/val/labels_yolo already exists\n",
86 | "[INFO] Directory dataset/icartoon/test/labels_yolo already exists\n",
87 | "[INFO] Directory dataset/animalweb/train/labels_yolo already exists\n",
88 | "[INFO] Directory dataset/animalweb/val/labels_yolo already exists\n",
89 | "[INFO] Directory dataset/animalweb/test/labels_yolo already exists\n",
90 | "[INFO] Directory dataset/tfw/train/labels_yolo already exists\n",
91 | "[INFO] Directory dataset/tfw/val/labels_yolo already exists\n",
92 | "[INFO] Directory dataset/tfw/test/labels_yolo already exists\n",
93 | "[INFO] Directory dataset/widerface/train/labels_yolo already exists\n",
94 | "[INFO] Directory dataset/widerface/val/labels_yolo already exists\n",
95 | "[INFO] Directory dataset/widerface/test/labels_yolo already exists\n"
96 | ]
97 | }
98 | ],
99 | "source": [
100 | "for d in dirs:\n",
101 | " for set_ in ['train', 'val', 'test']:\n",
102 | " make_dir(os.path.join(DATASET_PATH, d, set_, 'labels_yolo'))"
103 | ]
104 | },
105 | {
106 | "cell_type": "code",
107 | "execution_count": 26,
108 | "metadata": {},
109 | "outputs": [
110 | {
111 | "name": "stdout",
112 | "output_type": "stream",
113 | "text": [
114 | "icartoon train\n",
115 | "icartoon val\n",
116 | "icartoon test\n",
117 | "animalweb train\n",
118 | "animalweb val\n",
119 | "animalweb test\n",
120 | "tfw train\n",
121 | "tfw val\n",
122 | "tfw test\n",
123 | "widerface train\n",
124 | "widerface val\n",
125 | "widerface test\n"
126 | ]
127 | }
128 | ],
129 | "source": [
130 | "for d in dirs:\n",
131 | " for set_ in ['train', 'val', 'test']:\n",
132 | " annotPaths = list(paths.list_files(os.path.join(DATASET_PATH, d, set_, 'labels')))\n",
133 | " annotPaths = sorted(annotPaths)\n",
134 | " \n",
135 | " imagePaths = list(paths.list_files(os.path.join(DATASET_PATH, d, set_, 'images')))\n",
136 | " imagePaths = sorted(imagePaths)\n",
137 | " \n",
138 | " print(d, set_)\n",
139 | " \n",
140 | " for imagePath, annotPath in zip(imagePaths, annotPaths):\n",
141 | " image = cv2.imread(imagePath)\n",
142 | " H, W = image.shape[:2]\n",
143 | " \n",
144 | " f = open(annotPath, 'r')\n",
145 | " lines = f.readlines()\n",
146 | " \n",
147 | " yolo_txt_path = os.path.join(DATASET_PATH, d, set_, 'labels_yolo', annotPath.split('/')[-1])\n",
148 | " yolo_txt = open(yolo_txt_path, \"w\")\n",
149 | " \n",
150 | " for line in lines:\n",
151 | " line = line.split('\\n')[0]\n",
152 | " line = line.split(' ')\n",
153 | "\n",
154 | " coord = [float(i) for i in line[1:]]\n",
155 | "\n",
156 | " xs, ys, w, h, p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y, p5x, p5y = coord\n",
157 | " \n",
158 | " xc = xs + w / 2\n",
159 | " yc = ys + h / 2\n",
160 | " \n",
161 | " label_yolo = '0 {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f}\\n'.format(\n",
162 | " xc/W, yc/H, w/W, h/H, p1x/W, p1y/H, p2x/W, p2y/H, p3x/W, p3y/H, p4x/W, p4y/H, p5x/W, p5y/H) \n",
163 | " \n",
164 | " yolo_txt.write(label_yolo)\n",
165 | " \n",
166 | " yolo_txt.close()"
167 | ]
168 | },
169 | {
170 | "cell_type": "code",
171 | "execution_count": 27,
172 | "metadata": {},
173 | "outputs": [],
174 | "source": [
175 | "for d in dirs:\n",
176 | " for set_ in ['train', 'val', 'test']:\n",
177 | " src = os.path.join(DATASET_PATH, d, set_, 'labels')\n",
178 | " dst = os.path.join(DATASET_PATH, d, set_, 'labels_eval')\n",
179 | " os.rename(src, dst)\n",
180 | " \n",
181 | " src = os.path.join(DATASET_PATH, d, set_, 'labels_yolo')\n",
182 | " dst = os.path.join(DATASET_PATH, d, set_, 'labels')\n",
183 | " os.rename(src, dst)"
184 | ]
185 | },
186 | {
187 | "cell_type": "code",
188 | "execution_count": null,
189 | "metadata": {},
190 | "outputs": [],
191 | "source": []
192 | }
193 | ],
194 | "metadata": {
195 | "kernelspec": {
196 | "display_name": "Python 3",
197 | "language": "python",
198 | "name": "python3"
199 | },
200 | "language_info": {
201 | "codemirror_mode": {
202 | "name": "ipython",
203 | "version": 3
204 | },
205 | "file_extension": ".py",
206 | "mimetype": "text/x-python",
207 | "name": "python",
208 | "nbconvert_exporter": "python",
209 | "pygments_lexer": "ipython3",
210 | "version": "3.7.3"
211 | }
212 | },
213 | "nbformat": 4,
214 | "nbformat_minor": 4
215 | }
216 |
--------------------------------------------------------------------------------
/dataset/.gitignore:
--------------------------------------------------------------------------------
1 | # Ignore everything in this directory
2 | *
3 | # Except this file
4 | !.gitignore
--------------------------------------------------------------------------------
/original-external/.gitignore:
--------------------------------------------------------------------------------
1 | # Ignore everything in this directory
2 | *
3 | # Except this file
4 | !.gitignore
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | # pip install -r requirements.txt
2 |
3 | # Base ----------------------------------------
4 | matplotlib>=3.2.2
5 | numpy>=1.18.5
6 | opencv-python>=4.1.2
7 | Pillow>=7.1.2
8 | PyYAML>=5.3.1
9 | requests>=2.23.0
10 | scipy>=1.4.1
11 | tqdm>=4.41.0
12 |
13 | # Logging -------------------------------------
14 | tensorboard>=2.4.1
15 | # wandb
16 |
17 | # Plotting ------------------------------------
18 | pandas>=1.1.4
19 | seaborn>=0.11.0
20 |
21 | # Export --------------------------------------
22 | # coremltools>=4.1 # CoreML export
23 | # onnx>=1.9.0 # ONNX export
24 | # onnx-simplifier>=0.3.6 # ONNX simplifier
25 | # scikit-learn==0.19.2 # CoreML quantization
26 | # tensorflow>=2.4.1 # TFLite export
27 | # tensorflowjs>=3.9.0 # TF.js export
28 | # openvino-dev # OpenVINO export
29 |
30 | # Extras --------------------------------------
31 | # albumentations>=1.0.3
32 | # Cython # for pycocotools https://github.com/cocodataset/cocoapi/issues/172
33 | # pycocotools>=2.0 # COCO mAP
34 | # roboflow
35 | thop # FLOPs computation
--------------------------------------------------------------------------------
/selected-external/animefaces.txt:
--------------------------------------------------------------------------------
1 | 001706.jpg
2 | 002905.jpg
3 | 000914.jpg
4 | 006357.jpg
5 | 006021.jpg
6 | 006540.jpg
7 | 000026.jpg
8 | 003680.jpg
9 | 003816.jpg
10 | 004032.jpg
11 | 001513.jpg
12 | 003194.jpg
13 | 002223.jpg
14 | 006423.jpg
15 | 001166.jpg
16 | 000317.jpg
17 | 005823.jpg
18 | 003847.jpg
19 | 003724.jpg
20 | 002385.jpg
21 | 003503.jpg
22 | 001460.jpg
23 | 002910.jpg
24 | 004279.jpg
25 | 000702.jpg
26 | 000620.jpg
27 | 002956.jpg
28 | 001454.jpg
29 | 002327.jpg
30 | 002832.jpg
31 | 005291.jpg
32 | 005573.jpg
33 | 000304.jpg
34 | 002677.jpg
35 | 002149.jpg
36 | 001480.jpg
37 | 000958.jpg
38 | 003269.jpg
39 | 000619.jpg
40 | 006524.jpg
41 | 005884.jpg
42 | 006282.jpg
43 | 006587.jpg
44 | 006375.jpg
45 | 003226.jpg
46 | 000765.jpg
47 | 004266.jpg
48 | 004403.jpg
49 | 001306.jpg
50 | 002827.jpg
51 | 003945.jpg
52 | 000737.jpg
53 | 001892.jpg
54 | 006144.jpg
55 | 000714.jpg
56 | 003070.jpg
57 | 000966.jpg
58 | 006372.jpg
59 | 001669.jpg
60 | 005918.jpg
61 | 005950.jpg
62 | 002948.jpg
63 | 001385.jpg
64 | 002208.jpg
65 | 001237.jpg
66 | 002067.jpg
67 | 005849.jpg
68 | 004696.jpg
69 | 001805.jpg
70 | 004093.jpg
71 | 001666.jpg
72 | 004339.jpg
73 | 005676.jpg
74 | 004180.jpg
75 | 005221.jpg
76 | 003623.jpg
77 | 003381.jpg
78 | 006069.jpg
79 | 000578.jpg
80 | 004965.jpg
81 | 004318.jpg
82 | 003692.jpg
83 | 004554.jpg
84 | 000339.jpg
85 | 005510.jpg
86 | 001673.jpg
87 | 001199.jpg
88 | 004246.jpg
89 | 004437.jpg
90 | 003376.jpg
91 | 001631.jpg
92 | 001271.jpg
93 | 000174.jpg
94 | 001259.jpg
95 | 003187.jpg
96 | 001173.jpg
97 | 003796.jpg
98 | 004542.jpg
99 | 004349.jpg
100 | 002055.jpg
101 | 004919.jpg
102 | 003259.jpg
103 | 003080.jpg
104 | 000954.jpg
105 | 005624.jpg
106 | 005902.jpg
107 | 005992.jpg
108 | 005930.jpg
109 | 002166.jpg
110 | 003758.jpg
111 | 002441.jpg
112 | 006188.jpg
113 | 005150.jpg
114 | 000928.jpg
115 | 000084.jpg
116 | 004597.jpg
117 | 000237.jpg
118 | 003626.jpg
119 | 002393.jpg
120 | 002554.jpg
121 | 002739.jpg
122 | 004298.jpg
123 | 002962.jpg
124 | 000427.jpg
125 | 001744.jpg
126 | 000690.jpg
127 | 001294.jpg
128 | 005029.jpg
129 | 003397.jpg
130 | 002249.jpg
131 | 005080.jpg
132 | 000095.jpg
133 | 004612.jpg
134 | 002428.jpg
135 | 003438.jpg
136 | 003678.jpg
137 | 004857.jpg
138 | 005894.jpg
139 | 004623.jpg
140 | 006566.jpg
141 | 000942.jpg
142 | 000430.jpg
143 | 003647.jpg
144 | 002629.jpg
145 | 001146.jpg
146 | 005199.jpg
147 | 003935.jpg
148 | 004676.jpg
149 | 003855.jpg
150 | 005101.jpg
151 | 006430.jpg
152 | 001363.jpg
153 | 004261.jpg
154 | 004307.jpg
155 | 005261.jpg
156 | 000204.jpg
157 | 004456.jpg
158 | 002348.jpg
159 | 004504.jpg
160 | 001258.jpg
161 |
--------------------------------------------------------------------------------
/selected-external/artisticfaces.txt:
--------------------------------------------------------------------------------
1 | 28.png
2 | 31.png
3 | 130.png
4 | 125.png
5 | 27.png
6 | 49.png
7 | 111.png
8 | 118.png
9 | 7.png
10 | 129.png
11 | 122.png
12 | 144.png
13 | 88.png
14 | 134.png
15 | 83.png
16 | 92.png
17 | 77.png
18 | 74.png
19 | 158.png
20 | 6.png
21 | 146.png
22 | 159.png
23 | 3.png
24 | 113.png
25 | 38.png
26 | 142.png
27 | 57.png
28 | 97.png
29 | 8.png
30 | 34.png
31 | 133.png
32 | 137.png
33 | 124.png
34 | 138.png
35 | 84.png
36 | 139.png
37 | 151.png
38 | 29.png
39 | 157.png
40 | 14.png
41 | 70.png
42 | 99.png
43 | 100.png
44 | 17.png
45 | 55.png
46 | 67.png
47 | 32.png
48 | 11.png
49 | 145.png
50 | 117.png
51 | 98.png
52 | 72.png
53 | 44.png
54 | 52.png
55 | 135.png
56 | 58.png
57 | 154.png
58 | 143.png
59 | 65.png
60 | 148.png
61 | 96.png
62 | 132.png
63 | 82.png
64 | 64.png
65 | 2.png
66 | 63.png
67 | 114.png
68 | 4.png
69 | 47.png
70 | 5.png
71 | 59.png
72 | 107.png
73 | 123.png
74 | 108.png
75 | 16.png
76 | 93.png
77 | 80.png
78 | 90.png
79 | 50.png
80 | 95.png
81 | 66.png
82 | 13.png
83 | 156.png
84 | 126.png
85 | 12.png
86 | 33.png
87 | 105.png
88 | 56.png
89 | 20.png
90 | 62.png
91 | 68.png
92 | 51.png
93 | 53.png
94 | 23.png
95 | 110.png
96 | 76.png
97 | 78.png
98 | 15.png
99 | 22.png
100 | 115.png
101 | 75.png
102 | 43.png
103 | 85.png
104 | 41.png
105 | 69.png
106 | 86.png
107 | 104.png
108 | 45.png
109 | 26.png
110 | 40.png
111 | 30.png
112 | 152.png
113 | 147.png
114 | 37.png
115 | 106.png
116 | 141.png
117 | 42.png
118 | 19.png
119 | 46.png
120 | 101.png
121 | 102.png
122 | 9.png
123 | 60.png
124 | 127.png
125 | 140.png
126 | 71.png
127 | 54.png
128 | 131.png
129 | 18.png
130 | 119.png
131 | 112.png
132 | 24.png
133 | 121.png
134 | 103.png
135 | 10.png
136 | 116.png
137 | 120.png
138 | 73.png
139 | 155.png
140 | 36.png
141 | 81.png
142 | 153.png
143 | 128.png
144 | 149.png
145 | 61.png
146 | 39.png
147 | 48.png
148 | 136.png
149 | 94.png
150 | 91.png
151 | 35.png
152 | 109.png
153 | 87.png
154 | 25.png
155 | 150.png
156 | 0.png
157 | 89.png
158 | 79.png
159 | 1.png
160 | 21.png
161 |
--------------------------------------------------------------------------------
/selected-external/birds.txt:
--------------------------------------------------------------------------------
1 | Artic_Tern_0027_141617.jpg
2 | Black_Throated_Blue_Warbler_0004_161404.jpg
3 | Bohemian_Waxwing_0028_796647.jpg
4 | Hooded_Oriole_0091_90821.jpg
5 | European_Goldfinch_0025_794647.jpg
6 | Henslow_Sparrow_0108_796592.jpg
7 | Prothonotary_Warbler_0040_173447.jpg
8 | Yellow_Headed_Blackbird_0072_8606.jpg
9 | Chipping_Sparrow_0076_108919.jpg
10 | Red_Legged_Kittiwake_0019_795398.jpg
11 | Ring_Billed_Gull_0013_50180.jpg
12 | Bay_Breasted_Warbler_0081_159963.jpg
13 | Great_Grey_Shrike_0004_797041.jpg
14 | Glaucous_Winged_Gull_0078_44461.jpg
15 | Slaty_Backed_Gull_0087_786374.jpg
16 | Heermann_Gull_0075_45295.jpg
17 | Anna_Hummingbird_0054_56419.jpg
18 | Rock_Wren_0096_188966.jpg
19 | White_Breasted_Nuthatch_0119_86182.jpg
20 | Pigeon_Guillemot_0073_40209.jpg
21 | Wilson_Warbler_0010_175750.jpg
22 | Brewer_Sparrow_0049_796705.jpg
23 | Northern_Waterthrush_0073_177063.jpg
24 | Vesper_Sparrow_0073_125605.jpg
25 | Fish_Crow_0016_25854.jpg
26 | Baltimore_Oriole_0074_87214.jpg
27 | Orange_Crowned_Warbler_0040_168029.jpg
28 | Parakeet_Auklet_0028_795944.jpg
29 | Nighthawk_0070_82676.jpg
30 | Clark_Nutcracker_0101_85656.jpg
31 | Magnolia_Warbler_0102_165884.jpg
32 | Black_Tern_0023_143985.jpg
33 | Crested_Auklet_0059_794929.jpg
34 | American_Pipit_0111_99940.jpg
35 | Song_Sparrow_0099_121193.jpg
36 | Western_Gull_0104_53816.jpg
37 | Boat_Tailed_Grackle_0062_33650.jpg
38 | Bewick_Wren_0005_184699.jpg
39 | Cerulean_Warbler_0060_797209.jpg
40 | Le_Conte_Sparrow_0024_795190.jpg
41 | Rose_Breasted_Grosbeak_0086_39658.jpg
42 | Canada_Warbler_0115_162309.jpg
43 | Marsh_Wren_0076_188108.jpg
44 | Scarlet_Tanager_0130_138661.jpg
45 | Eastern_Towhee_0117_22741.jpg
46 | Savannah_Sparrow_0091_120630.jpg
47 | White_Necked_Raven_0019_797377.jpg
48 | Western_Grebe_0034_36149.jpg
49 | Ruby_Throated_Hummingbird_0034_58148.jpg
50 | White_Throated_Sparrow_0118_129084.jpg
51 | Red_Cockaded_Woodpecker_0050_794743.jpg
52 | Red_Bellied_Woodpecker_0007_182242.jpg
53 | Mallard_0055_77102.jpg
54 | Florida_Jay_0097_64906.jpg
55 | Olive_Sided_Flycatcher_0026_30525.jpg
56 | Rufous_Hummingbird_0089_59524.jpg
57 | Blue_Headed_Vireo_0122_156017.jpg
58 | Grasshopper_Sparrow_0039_115980.jpg
59 | Tennessee_Warbler_0096_174993.jpg
60 | Bank_Swallow_0064_129816.jpg
61 | Rusty_Blackbird_0120_6762.jpg
62 | Loggerhead_Shrike_0024_105593.jpg
63 | Yellow_Breasted_Chat_0101_21677.jpg
64 | Gray_Crowned_Rosy_Finch_0075_27165.jpg
65 | Northern_Flicker_0100_28898.jpg
66 | Seaside_Sparrow_0068_796515.jpg
67 | Northern_Fulmar_0098_43578.jpg
68 | Sayornis_0014_98889.jpg
69 | Red_Eyed_Vireo_0003_157226.jpg
70 | Least_Flycatcher_0019_30358.jpg
71 | Common_Yellowthroat_0018_190904.jpg
72 | Horned_Grebe_0061_34613.jpg
73 | Green_Violetear_0041_795648.jpg
74 | White_Crowned_Sparrow_0089_127778.jpg
75 | Black_And_White_Warbler_0053_160010.jpg
76 | Golden_Winged_Warbler_0056_794845.jpg
77 | Indigo_Bunting_0006_14317.jpg
78 | Cardinal_0084_17576.jpg
79 | Gadwall_0036_31760.jpg
80 | Prairie_Warbler_0130_172609.jpg
81 | Western_Meadowlark_0018_77880.jpg
82 | Red_Faced_Cormorant_0049_796279.jpg
83 | American_Three_Toed_Woodpecker_0020_179828.jpg
84 | Common_Tern_0062_147947.jpg
85 | Hooded_Merganser_0068_79057.jpg
86 | Red_Breasted_Merganser_0040_79207.jpg
87 | Warbling_Vireo_0052_158534.jpg
88 | Pine_Warbler_0065_172119.jpg
89 | Pileated_Woodpecker_0098_180170.jpg
90 | Spotted_Catbird_0020_796794.jpg
91 | Red_Winged_Blackbird_0075_4953.jpg
92 | Dark_Eyed_Junco_0008_68321.jpg
93 | Rhinoceros_Auklet_0007_797521.jpg
94 | Herring_Gull_0076_47497.jpg
95 | Pied_Billed_Grebe_0020_35958.jpg
96 | Green_Kingfisher_0093_71185.jpg
97 | Elegant_Tern_0093_150534.jpg
98 | Carolina_Wren_0036_186722.jpg
99 | American_Redstart_0013_103677.jpg
100 | Cedar_Waxwing_0101_179707.jpg
101 | Barn_Swallow_0089_131934.jpg
102 | Pacific_Loon_0042_75385.jpg
103 | Chuck_Will_Widow_0051_796991.jpg
104 | Long_Tailed_Jaeger_0011_60963.jpg
105 | Cactus_Wren_0079_185560.jpg
106 | Eared_Grebe_0048_34175.jpg
107 | Fox_Sparrow_0091_115550.jpg
108 | Lazuli_Bunting_0042_14820.jpg
109 | Nelson_Sharp_Tailed_Sparrow_0008_796944.jpg
110 | Blue_Jay_0003_63408.jpg
111 | Palm_Warbler_0075_168751.jpg
112 | Laysan_Albatross_0004_930.jpg
113 | Field_Sparrow_0063_113667.jpg
114 | Tropical_Kingbird_0087_69592.jpg
115 | Hooded_Warbler_0121_164639.jpg
116 | Brewer_Blackbird_0115_2279.jpg
117 | Black_Capped_Vireo_0003_797467.jpg
118 | Winter_Wren_0038_189510.jpg
119 | Brandt_Cormorant_0038_23110.jpg
120 | Baird_Sparrow_0035_106904.jpg
121 | Evening_Grosbeak_0004_37960.jpg
122 | Horned_Lark_0110_73826.jpg
123 | Gray_Catbird_0067_21043.jpg
124 | Kentucky_Warbler_0058_165441.jpg
125 | White_Eyed_Vireo_0019_159095.jpg
126 | Least_Tern_0089_152912.jpg
127 | Nashville_Warbler_0044_167357.jpg
128 | Forsters_Tern_0053_152175.jpg
129 | Yellow_Bellied_Flycatcher_0014_42608.jpg
130 | Sooty_Albatross_0007_796372.jpg
131 | Frigatebird_0112_43394.jpg
132 | House_Sparrow_0074_111997.jpg
133 | Pine_Grosbeak_0038_38956.jpg
134 | Cape_Glossy_Starling_0098_129365.jpg
135 | Philadelphia_Vireo_0035_156596.jpg
136 | American_Goldfinch_0026_32222.jpg
137 | Blue_Grosbeak_0042_36742.jpg
138 | Purple_Finch_0108_28143.jpg
139 | Brown_Thrasher_0119_155170.jpg
140 | Harris_Sparrow_0014_116494.jpg
141 | Mockingbird_0003_80833.jpg
142 | Least_Auklet_0045_795069.jpg
143 | Worm_Eating_Warbler_0034_795560.jpg
144 | Pied_Kingfisher_0085_71557.jpg
145 | Ovenbird_0020_93049.jpg
146 | Chestnut_Sided_Warbler_0073_163868.jpg
147 | Pelagic_Cormorant_0063_23515.jpg
148 | Black_Footed_Albatross_0080_796096.jpg
149 | Mourning_Warbler_0025_166608.jpg
150 | Geococcyx_0116_104240.jpg
151 | Whip_Poor_Will_0020_100396.jpg
152 | Vermilion_Flycatcher_0033_42522.jpg
153 | Lincoln_Sparrow_0042_117507.jpg
154 | Mangrove_Cuckoo_0022_794625.jpg
155 | Cape_May_Warbler_0004_162928.jpg
156 | Shiny_Cowbird_0030_24206.jpg
157 | Acadian_Flycatcher_0034_795583.jpg
158 | Blue_Winged_Warbler_0002_161890.jpg
159 | Bobolink_0001_9261.jpg
160 | Green_Jay_0003_65767.jpg
161 |
--------------------------------------------------------------------------------
/selected-external/metfaces.txt:
--------------------------------------------------------------------------------
1 | image-746938.png
2 | image-436627.png
3 | image-548585.png
4 | image-11602.png
5 | image-438737.png
6 | image-471908.png
7 | image-12827.png
8 | image-409000.png
9 | image-10929.png
10 | image-337431.png
11 | image-438020.png
12 | image-334760.png
13 | image-11843.png
14 | image-436028.png
15 | image-13094.png
16 | image-436584.png
17 | image-436190.png
18 | image-436825.png
19 | image-436315.png
20 | image-12662.png
21 | image-19022.png
22 | image-13045.png
23 | image-10528.png
24 | image-437900.png
25 | image-436152.png
26 | image-436045.png
27 | image-459127.png
28 | image-437904.png
29 | image-436657.png
30 | image-15173.png
31 | image-12533.png
32 | image-437358.png
33 | image-822756.png
34 | image-15233.png
35 | image-438603.png
36 | image-237070.png
37 | image-438819.png
38 | image-437420.png
39 | image-459253.png
40 | image-44833.png
41 | image-485.png
42 | image-10165.png
43 | image-437061.png
44 | image-435961.png
45 | image-11240.png
46 | image-11781.png
47 | image-435950.png
48 | image-436240.png
49 | image-436640.png
50 | image-10603.png
51 | image-12804.png
52 | image-436334.png
53 | image-436551.png
54 | image-436663.png
55 | image-11932.png
56 | image-828503.png
57 | image-11736.png
58 | image-33284.png
59 | image-199787.png
60 | image-436661.png
61 | image-242069.png
62 | image-775309.png
63 | image-337433.png
64 | image-436930.png
65 | image-10867.png
66 | image-438776.png
67 | image-11931.png
68 | image-10958.png
69 | image-13346.png
70 | image-49122.png
71 | image-436643.png
72 | image-437699.png
73 | image-436739.png
74 | image-15199.png
75 | image-437893.png
76 | image-13325.png
77 | image-437021.png
78 | image-813585.png
79 | image-436911.png
80 | image-459106.png
81 | image-435592.png
82 | image-437437.png
83 | image-12921.png
84 | image-436097.png
85 | image-547851.png
86 | image-436721.png
87 | image-14483.png
88 | image-11840.png
89 | image-437822.png
90 | image-436649.png
91 | image-437391.png
92 | image-436210.png
93 | image-485551.png
94 | image-49892.png
95 | image-11651.png
96 | image-10176.png
97 | image-15090.png
98 | image-15307.png
99 | image-436067.png
100 | image-544690.png
101 | image-436314.png
102 | image-436446.png
103 | image-11720.png
104 | image-437395.png
105 | image-11504.png
106 | image-231051.png
107 | image-338518.png
108 | image-336776.png
109 | image-390242.png
110 | image-390225.png
111 | image-231788.png
112 | image-435870.png
113 | image-435580.png
114 | image-441111.png
115 | image-29150.png
116 | image-247009.png
117 | image-10185.png
118 | image-12813.png
119 | image-708353.png
120 | image-436480.png
121 | image-435757.png
122 | image-438033.png
123 | image-392402.png
124 | image-437459.png
125 | image-742415.png
126 | image-735091.png
127 | image-436059.png
128 | image-631063.png
129 | image-11506.png
130 | image-10533.png
131 | image-436642.png
132 | image-435807.png
133 | image-436714.png
134 | image-15060.png
135 | image-435804.png
136 | image-437778.png
137 | image-12663.png
138 | image-13385.png
139 | image-414244.png
140 | image-551144.png
141 | image-436684.png
142 | image-437255.png
143 | image-11674.png
144 | image-10896.png
145 | image-11079.png
146 | image-10776.png
147 | image-12677.png
148 | image-322377.png
149 | image-506078.png
150 | image-435921.png
151 | image-437917.png
152 | image-38777.png
153 | image-435625.png
154 | image-459088.png
155 | image-362527.png
156 | image-13342.png
157 | image-544454.png
158 | image-13336.png
159 | image-10598.png
160 | image-436219.png
161 |
--------------------------------------------------------------------------------
/selected-external/pets.txt:
--------------------------------------------------------------------------------
1 | chihuahua_184.jpg
2 | miniature_pinscher_104.jpg
3 | Persian_12.jpg
4 | english_setter_126.jpg
5 | beagle_109.jpg
6 | Russian_Blue_151.jpg
7 | Sphynx_199.jpg
8 | pomeranian_177.jpg
9 | British_Shorthair_172.jpg
10 | yorkshire_terrier_138.jpg
11 | american_bulldog_188.jpg
12 | miniature_pinscher_16.jpg
13 | Maine_Coon_189.jpg
14 | staffordshire_bull_terrier_190.jpg
15 | Bengal_150.jpg
16 | Siamese_120.jpg
17 | Bombay_160.jpg
18 | pug_170.jpg
19 | pomeranian_153.jpg
20 | Ragdoll_177.jpg
21 | Siamese_122.jpg
22 | chihuahua_143.jpg
23 | english_setter_163.jpg
24 | japanese_chin_133.jpg
25 | Bengal_187.jpg
26 | British_Shorthair_109.jpg
27 | boxer_145.jpg
28 | leonberger_132.jpg
29 | basset_hound_169.jpg
30 | german_shorthaired_155.jpg
31 | german_shorthaired_187.jpg
32 | Birman_108.jpg
33 | samoyed_111.jpg
34 | Russian_Blue_174.jpg
35 | Ragdoll_198.jpg
36 | staffordshire_bull_terrier_183.jpg
37 | Maine_Coon_18.jpg
38 | beagle_122.jpg
39 | german_shorthaired_153.jpg
40 | leonberger_183.jpg
41 | pug_179.jpg
42 | keeshond_139.jpg
43 | yorkshire_terrier_185.jpg
44 | staffordshire_bull_terrier_158.jpg
45 | pomeranian_171.jpg
46 | Russian_Blue_130.jpg
47 | japanese_chin_141.jpg
48 | newfoundland_184.jpg
49 | keeshond_180.jpg
50 | Persian_201.jpg
51 | american_pit_bull_terrier_132.jpg
52 | Birman_187.jpg
53 | havanese_16.jpg
54 | saint_bernard_159.jpg
55 | Bengal_121.jpg
56 | staffordshire_bull_terrier_162.jpg
57 | Siamese_108.jpg
58 | keeshond_102.jpg
59 | Maine_Coon_135.jpg
60 | Birman_121.jpg
61 | Bengal_12.jpg
62 | Russian_Blue_168.jpg
63 | British_Shorthair_205.jpg
64 | great_pyrenees_118.jpg
65 | Birman_14.jpg
66 | japanese_chin_17.jpg
67 | english_setter_148.jpg
68 | scottish_terrier_124.jpg
69 | miniature_pinscher_187.jpg
70 | keeshond_105.jpg
71 | saint_bernard_13.jpg
72 | havanese_173.jpg
73 | american_pit_bull_terrier_148.jpg
74 | yorkshire_terrier_179.jpg
75 | Sphynx_143.jpg
76 | Ragdoll_110.jpg
77 | beagle_116.jpg
78 | basset_hound_143.jpg
79 | miniature_pinscher_135.jpg
80 | wheaten_terrier_187.jpg
81 | shiba_inu_118.jpg
82 | Persian_114.jpg
83 | Ragdoll_122.jpg
84 | english_setter_155.jpg
85 | Egyptian_Mau_164.jpg
86 | pomeranian_179.jpg
87 | Abyssinian_105.jpg
88 | scottish_terrier_183.jpg
89 | Abyssinian_112.jpg
90 | British_Shorthair_17.jpg
91 | great_pyrenees_107.jpg
92 | leonberger_120.jpg
93 | boxer_143.jpg
94 | Egyptian_Mau_136.jpg
95 | Egyptian_Mau_147.jpg
96 | basset_hound_155.jpg
97 | keeshond_179.jpg
98 | chihuahua_160.jpg
99 | scottish_terrier_155.jpg
100 | english_setter_149.jpg
101 | saint_bernard_128.jpg
102 | yorkshire_terrier_187.jpg
103 | american_bulldog_185.jpg
104 | german_shorthaired_130.jpg
105 | japanese_chin_144.jpg
106 | pomeranian_122.jpg
107 | yorkshire_terrier_133.jpg
108 | havanese_139.jpg
109 | english_cocker_spaniel_189.jpg
110 | great_pyrenees_127.jpg
111 | newfoundland_138.jpg
112 | great_pyrenees_154.jpg
113 | shiba_inu_171.jpg
114 | Bombay_156.jpg
115 | samoyed_164.jpg
116 | newfoundland_109.jpg
117 | beagle_192.jpg
118 | american_bulldog_109.jpg
119 | newfoundland_148.jpg
120 | wheaten_terrier_141.jpg
121 | pug_188.jpg
122 | english_cocker_spaniel_128.jpg
123 | saint_bernard_150.jpg
124 | pug_108.jpg
125 | samoyed_104.jpg
126 | Persian_106.jpg
127 | chihuahua_174.jpg
128 | shiba_inu_165.jpg
129 | Egyptian_Mau_116.jpg
130 | Egyptian_Mau_107.jpg
131 | english_cocker_spaniel_103.jpg
132 | shiba_inu_103.jpg
133 | Siamese_103.jpg
134 | Siamese_171.jpg
135 | pug_146.jpg
136 | Abyssinian_172.jpg
137 | Bombay_115.jpg
138 | american_pit_bull_terrier_182.jpg
139 | basset_hound_140.jpg
140 | samoyed_168.jpg
141 | Sphynx_114.jpg
142 | american_bulldog_128.jpg
143 | basset_hound_114.jpg
144 | Bombay_130.jpg
145 | scottish_terrier_177.jpg
146 | american_bulldog_124.jpg
147 | japanese_chin_175.jpg
148 | english_cocker_spaniel_100.jpg
149 | leonberger_187.jpg
150 | Abyssinian_16.jpg
151 | havanese_102.jpg
152 | Bombay_137.jpg
153 | Sphynx_206.jpg
154 | Persian_103.jpg
155 | havanese_14.jpg
156 | boxer_129.jpg
157 | wheaten_terrier_15.jpg
158 | wheaten_terrier_183.jpg
159 | boxer_172.jpg
160 | wheaten_terrier_100.jpg
161 |
--------------------------------------------------------------------------------
/selected-external/tj.txt:
--------------------------------------------------------------------------------
1 | frame66.jpg
2 | frame181.jpg
3 | frame142.jpg
4 | frame145.jpg
5 | frame157.jpg
6 | test158.jpg
7 | test42.jpg
8 | test181.jpg
9 | frame206.jpg
10 | test77.jpg
11 | frame234.jpg
12 | test152.jpg
13 | frame87.jpg
14 | test178.jpg
15 | frame208.jpg
16 | frame178.jpg
17 | test32.jpg
18 | test96.jpg
19 | frame50.jpg
20 | test108.jpg
21 | frame41.jpg
22 | test11.jpg
23 | test20.jpg
24 | frame34.jpg
25 | test56.jpg
26 | frame16.jpg
27 | frame167.jpg
28 | test24.jpg
29 | frame251.jpg
30 | frame96.jpg
31 | test29.jpg
32 | frame172.jpg
33 | test120.jpg
34 | frame203.jpg
35 | test171.jpg
36 | frame135.jpg
37 | frame192.jpg
38 | frame207.jpg
39 | test92.jpg
40 | test162.jpg
41 | frame63.jpg
42 | frame254.jpg
43 | test166.jpg
44 | test138.jpg
45 | frame52.jpg
46 | test18.jpg
47 | test128.jpg
48 | test124.jpg
49 | frame45.jpg
50 | frame233.jpg
51 | test107.jpg
52 | test155.jpg
53 | frame232.jpg
54 | test97.jpg
55 | frame193.jpg
56 | test161.jpg
57 | test134.jpg
58 | test86.jpg
59 | frame202.jpg
60 | test174.jpg
61 | frame231.jpg
62 | test150.jpg
63 | frame47.jpg
64 | frame212.jpg
65 | test184.jpg
66 | frame133.jpg
67 | test159.jpg
68 | test172.jpg
69 | frame149.jpg
70 | frame179.jpg
71 | frame71.jpg
72 | frame261.jpg
73 | frame80.jpg
74 | frame130.jpg
75 | frame84.jpg
76 | frame29.jpg
77 | frame176.jpg
78 | test147.jpg
79 | test36.jpg
80 | test83.jpg
81 | frame258.jpg
82 | test12.jpg
83 | frame85.jpg
84 | frame148.jpg
85 | frame259.jpg
86 | frame28.jpg
87 | test91.jpg
88 | frame123.jpg
89 | test58.jpg
90 | test21.jpg
91 | test109.jpg
92 | test72.jpg
93 | test1.jpg
94 | test49.jpg
95 | frame91.jpg
96 | test182.jpg
97 | test170.jpg
98 | frame271.jpg
99 | test149.jpg
100 | frame5.jpg
101 | test154.jpg
102 | frame189.jpg
103 | frame60.jpg
104 | test130.jpg
105 | test44.jpg
106 | test65.jpg
107 | frame53.jpg
108 | frame154.jpg
109 | frame124.jpg
110 | frame240.jpg
111 | test121.jpg
112 | frame201.jpg
113 | frame200.jpg
114 | test19.jpg
115 | test23.jpg
116 | frame169.jpg
117 | frame228.jpg
118 | frame2.jpg
119 | frame23.jpg
120 | test99.jpg
121 | frame151.jpg
122 | frame237.jpg
123 | test76.jpg
124 | frame209.jpg
125 | test105.jpg
126 | test113.jpg
127 | test157.jpg
128 | test141.jpg
129 | test4.jpg
130 | frame6.jpg
131 | frame35.jpg
132 | test114.jpg
133 | frame163.jpg
134 | frame22.jpg
135 | frame56.jpg
136 | frame20.jpg
137 | test167.jpg
138 | frame31.jpg
139 | test111.jpg
140 | test135.jpg
141 | test43.jpg
142 | frame129.jpg
143 | test57.jpg
144 | frame278.jpg
145 | frame183.jpg
146 | test103.jpg
147 | frame277.jpg
148 | test118.jpg
149 | frame256.jpg
150 | frame0.jpg
151 | test52.jpg
152 | test61.jpg
153 | test8.jpg
154 | frame143.jpg
155 | frame152.jpg
156 | test50.jpg
157 | frame229.jpg
158 | test95.jpg
159 | frame170.jpg
160 | test25.jpg
161 |
--------------------------------------------------------------------------------
/selected-external/turtles.txt:
--------------------------------------------------------------------------------
1 | Image_450.jpg
2 | Image_1555.jpg
3 | Image_1056.jpg
4 | Image_1082.jpg
5 | Image_62.jpg
6 | Image_343.jpg
7 | Image_1514.jpg
8 | Image_1589.jpg
9 | Image_91.jpg
10 | Image_306.jpg
11 | Image_935.jpg
12 | Image_1172.jpg
13 | Image_482.jpg
14 | Image_5.jpg
15 | Image_1314.jpg
16 | Image_957.jpg
17 | Image_1880.jpg
18 | Image_1183.jpg
19 | Image_29.jpg
20 | Image_270.jpg
21 | Image_399.jpg
22 | Image_1451.jpg
23 | Image_1089.jpg
24 | Image_862.jpg
25 | Image_225.jpg
26 | Image_1676.jpg
27 | Image_532.jpg
28 | Image_982.jpg
29 | Image_46.jpg
30 | Image_1310.png
31 | Image_1167.jpg
32 | Image_319.jpg
33 | Image_1922.jpg
34 | Image_1762.jpg
35 | Image_822.jpg
36 | Image_194.jpg
37 | Image_1270.jpg
38 | Image_1520.jpg
39 | Image_1301.jpg
40 | Image_63.jpg
41 | Image_491.jpg
42 | Image_1733.jpg
43 | Image_1131.jpg
44 | Image_594.jpg
45 | Image_500.jpg
46 | Image_1127.jpg
47 | Image_17.jpg
48 | Image_1199.jpg
49 | Image_1775.jpg
50 | Image_773.jpg
51 | Image_142.jpg
52 | Image_8.jpg
53 | Image_1532.jpg
54 | Image_1821.jpg
55 | Image_51.jpg
56 | Image_621.jpg
57 | Image_157.jpg
58 | Image_620.jpg
59 | Image_243.jpg
60 | Image_544.jpg
61 | Image_1400.jpg
62 | Image_470.jpg
63 | Image_1801.jpg
64 | Image_880.jpg
65 | Image_1992.jpg
66 | Image_1892.jpg
67 | Image_1887.jpg
68 | Image_1042.jpg
69 | Image_1112.jpg
70 | Image_296.jpg
71 | Image_480.jpg
72 | Image_657.jpg
73 | Image_1348.jpg
74 | Image_138.jpg
75 | Image_83.jpg
76 | Image_759.jpg
77 | Image_70.jpg
78 | Image_1569.jpg
79 | Image_1635.jpg
80 | Image_565.jpg
81 | Image_829.jpg
82 | Image_527.jpg
83 | Image_3.jpg
84 | Image_1582.jpg
85 | Image_1196.jpg
86 | Image_1791.jpg
87 | Image_1692.jpg
88 | Image_1490.jpg
89 | Image_683.jpg
90 | Image_174.jpg
91 | Image_997.jpg
92 | Image_37.jpg
93 | Image_1859.jpg
94 | Image_1748.jpg
95 | Image_992.jpg
96 | Image_1462.jpg
97 | Image_1518.jpg
98 | Image_461.jpg
99 | Image_1358.jpg
100 | Image_1407.jpg
101 | Image_1626.jpg
102 | Image_629.jpg
103 | Image_102.jpg
104 | Image_1952.jpg
105 | Image_1486.jpg
106 | Image_1534.jpg
107 | Image_362.jpg
108 | Image_305.jpg
109 | Image_819.jpg
110 | Image_184.jpg
111 | Image_933.jpg
112 | Image_758.jpg
113 | Image_876.jpg
114 | Image_414.jpg
115 | Image_1722.jpg
116 | Image_1739.jpg
117 | Image_1841.jpg
118 | Image_1989.jpg
119 | Image_1770.jpg
120 | Image_1103.jpg
121 | Image_1906.jpg
122 | Image_1120.jpg
123 | Image_1585.jpg
124 | Image_883.jpg
125 | Image_1487.jpg
126 | Image_1738.jpg
127 | Image_137.jpg
128 | Image_1438.jpg
129 | Image_1925.jpg
130 | Image_1140.jpg
131 | Image_1542.jpg
132 | Image_232.jpg
133 | Image_1543.jpg
134 | Image_299.jpg
135 | Image_1535.jpg
136 | Image_218.jpg
137 | Image_576.jpg
138 | Image_1718.jpg
139 | Image_619.jpg
140 | Image_493.jpg
141 | Image_1817.jpg
142 | Image_1485.jpg
143 | Image_1822.jpg
144 | Image_1080.jpg
145 | Image_1829.jpg
146 | Image_1858.jpg
147 | Image_780.jpg
148 | Image_577.jpg
149 | Image_79.jpg
150 | Image_1137.jpg
151 | Image_865.jpg
152 | Image_837.jpg
153 | Image_220.jpg
154 | Image_952.jpg
155 | Image_411.jpg
156 | Image_369.jpg
157 | Image_750.jpg
158 | Image_1477.jpg
159 | Image_860.jpg
160 | Image_1156.jpg
161 |
--------------------------------------------------------------------------------
/test_images/.gitignore:
--------------------------------------------------------------------------------
1 | # Ignore everything in this directory
2 | *
3 | # Except this file
4 | !.gitignore
--------------------------------------------------------------------------------
/test_videos/.gitignore:
--------------------------------------------------------------------------------
1 | # Ignore everything in this directory
2 | *
3 | # Except this file
4 | !.gitignore
--------------------------------------------------------------------------------
/tfw_preprocessing.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": 1,
6 | "metadata": {},
7 | "outputs": [],
8 | "source": [
9 | "from imutils import paths \n",
10 | "from shutil import copyfile\n",
11 | "import pandas as pd\n",
12 | "import numpy as np\n",
13 | "import csv\n",
14 | "import os"
15 | ]
16 | },
17 | {
18 | "cell_type": "code",
19 | "execution_count": 2,
20 | "metadata": {},
21 | "outputs": [],
22 | "source": [
23 | "def make_dir(dirName):\n",
24 | " # Create a target directory & all intermediate \n",
25 | " # directories if they don't exists\n",
26 | " if not os.path.exists(dirName):\n",
27 | " os.makedirs(dirName, exist_ok = True)\n",
28 | " print(\"[INFO] Directory \" , dirName , \" created\")\n",
29 | " else:\n",
30 | " print(\"[INFO] Directory \" , dirName , \" already exists\")"
31 | ]
32 | },
33 | {
34 | "cell_type": "code",
35 | "execution_count": 3,
36 | "metadata": {},
37 | "outputs": [
38 | {
39 | "name": "stdout",
40 | "output_type": "stream",
41 | "text": [
42 | "[INFO] Directory dataset/tfw/train/images created\n",
43 | "[INFO] Directory dataset/tfw/train/labels created\n",
44 | "[INFO] Directory dataset/tfw/test/images created\n",
45 | "[INFO] Directory dataset/tfw/test/labels created\n",
46 | "[INFO] Directory dataset/tfw/val/images created\n",
47 | "[INFO] Directory dataset/tfw/val/labels created\n"
48 | ]
49 | }
50 | ],
51 | "source": [
52 | "# Define dataset directories\n",
53 | "SOURCE_PATH = 'TFW/'\n",
54 | "TARGET_PATH = 'dataset/tfw'\n",
55 | "\n",
56 | "# Define and make directories for training, validation and testing sets\n",
57 | "TRAIN_IMG_DIR = 'train/images'\n",
58 | "TRAIN_LAB_DIR = 'train/labels'\n",
59 | "make_dir(os.path.join(TARGET_PATH, TRAIN_IMG_DIR))\n",
60 | "make_dir(os.path.join(TARGET_PATH, TRAIN_LAB_DIR))\n",
61 | "\n",
62 | "TEST_IMG_DIR = 'test/images'\n",
63 | "TEST_LAB_DIR = 'test/labels'\n",
64 | "make_dir(os.path.join(TARGET_PATH, TEST_IMG_DIR))\n",
65 | "make_dir(os.path.join(TARGET_PATH, TEST_LAB_DIR))\n",
66 | "\n",
67 | "VAL_IMG_DIR = 'val/images'\n",
68 | "VAL_LAB_DIR = 'val/labels'\n",
69 | "make_dir(os.path.join(TARGET_PATH, VAL_IMG_DIR))\n",
70 | "make_dir(os.path.join(TARGET_PATH, VAL_LAB_DIR))"
71 | ]
72 | },
73 | {
74 | "cell_type": "code",
75 | "execution_count": 4,
76 | "metadata": {},
77 | "outputs": [],
78 | "source": [
79 | "def convert(source_path, target_path, set_='train', env='indoor'):\n",
80 | " img_path = os.path.join(source_path, set_, env+\"_gray\")\n",
81 | " csv_file = os.path.join(source_path, set_, '{}.csv'.format(env))\n",
82 | " \n",
83 | " # import labels as a numpy array\n",
84 | " labels = pd.read_csv(csv_file,header=0).to_numpy()\n",
85 | "\n",
86 | " # initialize iterators\n",
87 | " iter1 = 0 \n",
88 | " iter2 = 0\n",
89 | "\n",
90 | " # init counters\n",
91 | " face_count = 0\n",
92 | " image_count = 0\n",
93 | "\n",
94 | " # loop over the rows\n",
95 | " while iter1 < len(labels):\n",
96 | " # load the image\n",
97 | " imageName = labels[iter1][0]\n",
98 | " \n",
99 | " if imageName.split('_')[-1][0] != 'm':\n",
100 | " image_count += 1\n",
101 | " source_img = os.path.join(img_path, imageName)\n",
102 | " \n",
103 | " target_img = os.path.join(target_path, set_, 'images', imageName)\n",
104 | " target_txt = open(os.path.join(target_path, set_,\n",
105 | " 'labels/{}.txt'.format(imageName.split('.png')[0])), \"w\")\n",
106 | " \n",
107 | " copyfile(source_img, target_img)\n",
108 | " \n",
109 | " # loop over the labels of this image\n",
110 | " while labels[iter1][0] == labels[iter2][0]:\n",
111 | " if imageName.split('_')[-1][0] != 'm':\n",
112 | " # extract coordinates of the bounding box and five facial landmarks\n",
113 | " xs, ys, xe, ye, p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y, p5x, p5y = labels[iter2][1:]\n",
114 | " label = 'face {} {} {} {} {} {} {} {} {} {} {} {} {} {}\\n'.format(xs, ys, xe-xs, ye-ys, p1x, p1y, p2x, p2y, \n",
115 | " p3x, p3y, p4x, p4y, p5x, p5y)\n",
116 | " target_txt.write(label)\n",
117 | " face_count += 1\n",
118 | " \n",
119 | " iter2 += 1\n",
120 | " \n",
121 | " # break the loop if we exceeded\n",
122 | " # the last row\n",
123 | " if iter2 == len(labels):\n",
124 | " break\n",
125 | " \n",
126 | " # equalize iterators\n",
127 | " iter1 = iter2\n",
128 | "\n",
129 | " print(image_count, face_count)"
130 | ]
131 | },
132 | {
133 | "cell_type": "code",
134 | "execution_count": 5,
135 | "metadata": {},
136 | "outputs": [
137 | {
138 | "name": "stdout",
139 | "output_type": "stream",
140 | "text": [
141 | "3600 3600\n"
142 | ]
143 | }
144 | ],
145 | "source": [
146 | "convert(SOURCE_PATH, TARGET_PATH, set_='train', env='indoor')"
147 | ]
148 | },
149 | {
150 | "cell_type": "code",
151 | "execution_count": 6,
152 | "metadata": {},
153 | "outputs": [
154 | {
155 | "name": "stdout",
156 | "output_type": "stream",
157 | "text": [
158 | "2958 7201\n"
159 | ]
160 | }
161 | ],
162 | "source": [
163 | "convert(SOURCE_PATH, TARGET_PATH, set_='train', env='outdoor')"
164 | ]
165 | },
166 | {
167 | "cell_type": "code",
168 | "execution_count": 7,
169 | "metadata": {},
170 | "outputs": [
171 | {
172 | "name": "stdout",
173 | "output_type": "stream",
174 | "text": [
175 | "432 432\n"
176 | ]
177 | }
178 | ],
179 | "source": [
180 | "convert(SOURCE_PATH, TARGET_PATH, set_='val', env='indoor')"
181 | ]
182 | },
183 | {
184 | "cell_type": "code",
185 | "execution_count": 8,
186 | "metadata": {},
187 | "outputs": [
188 | {
189 | "name": "stdout",
190 | "output_type": "stream",
191 | "text": [
192 | "332 649\n"
193 | ]
194 | }
195 | ],
196 | "source": [
197 | "convert(SOURCE_PATH, TARGET_PATH, set_='val', env='outdoor')"
198 | ]
199 | },
200 | {
201 | "cell_type": "code",
202 | "execution_count": 9,
203 | "metadata": {},
204 | "outputs": [
205 | {
206 | "name": "stdout",
207 | "output_type": "stream",
208 | "text": [
209 | "1080 1080\n"
210 | ]
211 | }
212 | ],
213 | "source": [
214 | "convert(SOURCE_PATH, TARGET_PATH, set_='test', env='indoor')"
215 | ]
216 | },
217 | {
218 | "cell_type": "code",
219 | "execution_count": 10,
220 | "metadata": {},
221 | "outputs": [
222 | {
223 | "name": "stdout",
224 | "output_type": "stream",
225 | "text": [
226 | "800 1799\n"
227 | ]
228 | }
229 | ],
230 | "source": [
231 | "convert(SOURCE_PATH, TARGET_PATH, set_='test', env='outdoor')"
232 | ]
233 | },
234 | {
235 | "cell_type": "code",
236 | "execution_count": null,
237 | "metadata": {},
238 | "outputs": [],
239 | "source": []
240 | }
241 | ],
242 | "metadata": {
243 | "kernelspec": {
244 | "display_name": "Python 3",
245 | "language": "python",
246 | "name": "python3"
247 | },
248 | "language_info": {
249 | "codemirror_mode": {
250 | "name": "ipython",
251 | "version": 3
252 | },
253 | "file_extension": ".py",
254 | "mimetype": "text/x-python",
255 | "name": "python",
256 | "nbconvert_exporter": "python",
257 | "pygments_lexer": "ipython3",
258 | "version": "3.7.3"
259 | }
260 | },
261 | "nbformat": 4,
262 | "nbformat_minor": 4
263 | }
264 |
--------------------------------------------------------------------------------
/widerface_preprocessing.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": 1,
6 | "metadata": {},
7 | "outputs": [],
8 | "source": [
9 | "from imutils import paths \n",
10 | "from shutil import copyfile\n",
11 | "import os"
12 | ]
13 | },
14 | {
15 | "cell_type": "code",
16 | "execution_count": 2,
17 | "metadata": {},
18 | "outputs": [],
19 | "source": [
20 | "def make_dir(dirName):\n",
21 | " # Create a target directory & all intermediate \n",
22 | " # directories if they don't exists\n",
23 | " if not os.path.exists(dirName):\n",
24 | " os.makedirs(dirName, exist_ok = True)\n",
25 | " print(\"[INFO] Directory \" , dirName , \" created\")\n",
26 | " else:\n",
27 | " print(\"[INFO] Directory \" , dirName , \" already exists\")"
28 | ]
29 | },
30 | {
31 | "cell_type": "code",
32 | "execution_count": 3,
33 | "metadata": {},
34 | "outputs": [
35 | {
36 | "name": "stdout",
37 | "output_type": "stream",
38 | "text": [
39 | "[INFO] Directory dataset/widerface/train/images created\n",
40 | "[INFO] Directory dataset/widerface/train/labels created\n",
41 | "[INFO] Directory dataset/widerface/test/images created\n",
42 | "[INFO] Directory dataset/widerface/test/labels created\n",
43 | "[INFO] Directory dataset/widerface/val/images created\n",
44 | "[INFO] Directory dataset/widerface/val/labels created\n"
45 | ]
46 | }
47 | ],
48 | "source": [
49 | "# Define dataset directories\n",
50 | "SOURCE_PATH = 'widerface'\n",
51 | "TARGET_PATH = 'dataset/widerface'\n",
52 | "\n",
53 | "# Define and make directories for training, validation and testing sets\n",
54 | "TRAIN_IMG_DIR = 'train/images'\n",
55 | "TRAIN_LAB_DIR = 'train/labels'\n",
56 | "make_dir(os.path.join(TARGET_PATH, TRAIN_IMG_DIR))\n",
57 | "make_dir(os.path.join(TARGET_PATH, TRAIN_LAB_DIR))\n",
58 | "\n",
59 | "TEST_IMG_DIR = 'test/images'\n",
60 | "TEST_LAB_DIR = 'test/labels'\n",
61 | "make_dir(os.path.join(TARGET_PATH, TEST_IMG_DIR))\n",
62 | "make_dir(os.path.join(TARGET_PATH, TEST_LAB_DIR))\n",
63 | "\n",
64 | "VAL_IMG_DIR = 'val/images'\n",
65 | "VAL_LAB_DIR = 'val/labels'\n",
66 | "make_dir(os.path.join(TARGET_PATH, VAL_IMG_DIR))\n",
67 | "make_dir(os.path.join(TARGET_PATH, VAL_LAB_DIR))"
68 | ]
69 | },
70 | {
71 | "cell_type": "code",
72 | "execution_count": 8,
73 | "metadata": {},
74 | "outputs": [],
75 | "source": [
76 | "def convert(source_path, target_path, set_='train'):\n",
77 | " source_txt = os.path.join(source_path, set_, 'label.txt')\n",
78 | " face_counter = 0\n",
79 | " image_counter = 0\n",
80 | " f = open(source_txt, 'r')\n",
81 | " \n",
82 | " lines = f.readlines()\n",
83 | " \n",
84 | " for line in lines:\n",
85 | " line = line.split(' ')\n",
86 | " \n",
87 | " if line[0] == '#':\n",
88 | " source_img = os.path.join(source_path, set_, 'images', line[1].split('\\n')[0])\n",
89 | " target_img = os.path.join(target_path, set_, 'images', line[1].split('/')[-1].split('\\n')[0])\n",
90 | " image_counter += 1\n",
91 | " copyfile(source_img, target_img)\n",
92 | " \n",
93 | " if set_ != 'test':\n",
94 | " target_txt = open(os.path.join(target_path, set_,\n",
95 | " 'labels/{}.txt'.format(line[1].split('/')[-1].split('.jpg')[0])), \"w\")\n",
96 | " else:\n",
97 | " face_counter += 1\n",
98 | " line = [float(i) for i in line[:18]]\n",
99 | " if set_ == 'train':\n",
100 | " label = 'face {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f}\\n'.format(\n",
101 | " line[0], line[1], line[2], line[3], # left, top, width, height \n",
102 | " line[4], line[5], line[7], line[8], line[10], line[11], line[13], # p1x,p1y,p2x,p2y,p3x,p3y \n",
103 | " line[14], line[16], line[17]) # p4x,p4y,p5x,p5y\n",
104 | " else:\n",
105 | " label = 'face {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f}\\n'.format(\n",
106 | " line[0], line[1], line[2], line[3], # xs, ys, xe, ye \n",
107 | " -1, -1, -1, -1, -1, -1, -1, # p1x,p1y,p2x,p2y,p3x,p3y \n",
108 | " -1, -1, -1) # p4x,p4y,p5x,p5y \n",
109 | " \n",
110 | " target_txt.write(label)\n",
111 | " \n",
112 | " print(image_counter, face_counter)"
113 | ]
114 | },
115 | {
116 | "cell_type": "code",
117 | "execution_count": 9,
118 | "metadata": {},
119 | "outputs": [
120 | {
121 | "name": "stdout",
122 | "output_type": "stream",
123 | "text": [
124 | "12880 159424\n"
125 | ]
126 | }
127 | ],
128 | "source": [
129 | "convert(SOURCE_PATH, TARGET_PATH, set_='train')"
130 | ]
131 | },
132 | {
133 | "cell_type": "code",
134 | "execution_count": 10,
135 | "metadata": {},
136 | "outputs": [
137 | {
138 | "name": "stdout",
139 | "output_type": "stream",
140 | "text": [
141 | "3226 39708\n"
142 | ]
143 | }
144 | ],
145 | "source": [
146 | "convert(SOURCE_PATH, TARGET_PATH, set_='val')"
147 | ]
148 | },
149 | {
150 | "cell_type": "code",
151 | "execution_count": 11,
152 | "metadata": {},
153 | "outputs": [
154 | {
155 | "name": "stdout",
156 | "output_type": "stream",
157 | "text": [
158 | "16097 0\n"
159 | ]
160 | }
161 | ],
162 | "source": [
163 | "convert(SOURCE_PATH, TARGET_PATH, set_='test')"
164 | ]
165 | },
166 | {
167 | "cell_type": "code",
168 | "execution_count": null,
169 | "metadata": {},
170 | "outputs": [],
171 | "source": []
172 | }
173 | ],
174 | "metadata": {
175 | "kernelspec": {
176 | "display_name": "Python 3",
177 | "language": "python",
178 | "name": "python3"
179 | },
180 | "language_info": {
181 | "codemirror_mode": {
182 | "name": "ipython",
183 | "version": 3
184 | },
185 | "file_extension": ".py",
186 | "mimetype": "text/x-python",
187 | "name": "python",
188 | "nbconvert_exporter": "python",
189 | "pygments_lexer": "ipython3",
190 | "version": "3.7.3"
191 | }
192 | },
193 | "nbformat": 4,
194 | "nbformat_minor": 4
195 | }
196 |
--------------------------------------------------------------------------------
/yolov5-face/data/agnostic.yaml:
--------------------------------------------------------------------------------
1 | # train and val data as 1) directory: path/images/, 2) file: path/images.txt, or 3) list: [path1/images/, path2/images/]
2 | # train: ['/workspace/datasets/animal/train/images/', '/workspace/datasets/widerface/train/images/', '/workspace/datasets/icartoon/train/images/', '/workspace/datasets/tfw/train/images/']
3 | # val: ['/workspace/datasets/animal/val/images/', '/workspace/datasets/widerface/val/images/', '/workspace/datasets/icartoon/val/images/', '/workspace/datasets/tfw/val/images/']
4 |
5 | train: ['/workspace/dataset/icartoon/train/images/', '/workspace/dataset/widerface/train/images/', '/workspace/dataset/animalweb/train/images/', '/workspace/dataset/tfw/train/images/']
6 | val: ['/workspace/dataset/icartoon/val/images/', '/workspace/dataset/widerface/val/images/', '/workspace/dataset/animalweb/val/images/', '/workspace/dataset/tfw/val/images/']
7 |
8 | # train: ['/workspace/datasets/animal/train/images/', '/workspace/datasets/tfw/train/images/']
9 | # val: ['/workspace/datasets/animal/val/images/', '/workspace/datasets/tfw/val/images/']
10 |
11 |
12 | # number of classes
13 | nc: 1
14 |
15 | # class names
16 | names: [ 'face']
17 |
--------------------------------------------------------------------------------
/yolov5-face/data/argoverse_hd.yaml:
--------------------------------------------------------------------------------
1 | # Argoverse-HD dataset (ring-front-center camera) http://www.cs.cmu.edu/~mengtial/proj/streaming/
2 | # Train command: python train.py --data argoverse_hd.yaml
3 | # Default dataset location is next to /yolov5:
4 | # /parent_folder
5 | # /argoverse
6 | # /yolov5
7 |
8 |
9 | # download command/URL (optional)
10 | download: bash data/scripts/get_argoverse_hd.sh
11 |
12 | # train and val data as 1) directory: path/images/, 2) file: path/images.txt, or 3) list: [path1/images/, path2/images/]
13 | train: ../argoverse/Argoverse-1.1/images/train/ # 39384 images
14 | val: ../argoverse/Argoverse-1.1/images/val/ # 15062 iamges
15 | test: ../argoverse/Argoverse-1.1/images/test/ # Submit to: https://eval.ai/web/challenges/challenge-page/800/overview
16 |
17 | # number of classes
18 | nc: 8
19 |
20 | # class names
21 | names: [ 'person', 'bicycle', 'car', 'motorcycle', 'bus', 'truck', 'traffic_light', 'stop_sign' ]
22 |
--------------------------------------------------------------------------------
/yolov5-face/data/coco.yaml:
--------------------------------------------------------------------------------
1 | # COCO 2017 dataset http://cocodataset.org
2 | # Train command: python train.py --data coco.yaml
3 | # Default dataset location is next to /yolov5:
4 | # /parent_folder
5 | # /coco
6 | # /yolov5
7 |
8 |
9 | # download command/URL (optional)
10 | download: bash data/scripts/get_coco.sh
11 |
12 | # train and val data as 1) directory: path/images/, 2) file: path/images.txt, or 3) list: [path1/images/, path2/images/]
13 | train: ../coco/train2017.txt # 118287 images
14 | val: ../coco/val2017.txt # 5000 images
15 | test: ../coco/test-dev2017.txt # 20288 of 40670 images, submit to https://competitions.codalab.org/competitions/20794
16 |
17 | # number of classes
18 | nc: 80
19 |
20 | # class names
21 | names: [ 'person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light',
22 | 'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow',
23 | 'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee',
24 | 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard',
25 | 'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple',
26 | 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch',
27 | 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone',
28 | 'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear',
29 | 'hair drier', 'toothbrush' ]
30 |
31 | # Print classes
32 | # with open('data/coco.yaml') as f:
33 | # d = yaml.load(f, Loader=yaml.FullLoader) # dict
34 | # for i, x in enumerate(d['names']):
35 | # print(i, x)
36 |
--------------------------------------------------------------------------------
/yolov5-face/data/coco128.yaml:
--------------------------------------------------------------------------------
1 | # COCO 2017 dataset http://cocodataset.org - first 128 training images
2 | # Train command: python train.py --data coco128.yaml
3 | # Default dataset location is next to /yolov5:
4 | # /parent_folder
5 | # /coco128
6 | # /yolov5
7 |
8 |
9 | # download command/URL (optional)
10 | download: https://github.com/ultralytics/yolov5/releases/download/v1.0/coco128.zip
11 |
12 | # train and val data as 1) directory: path/images/, 2) file: path/images.txt, or 3) list: [path1/images/, path2/images/]
13 | train: ../coco128/images/train2017/ # 128 images
14 | val: ../coco128/images/train2017/ # 128 images
15 |
16 | # number of classes
17 | nc: 80
18 |
19 | # class names
20 | names: [ 'person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light',
21 | 'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow',
22 | 'elephant', 'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee',
23 | 'skis', 'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard',
24 | 'tennis racket', 'bottle', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple',
25 | 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch',
26 | 'potted plant', 'bed', 'dining table', 'toilet', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone',
27 | 'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'book', 'clock', 'vase', 'scissors', 'teddy bear',
28 | 'hair drier', 'toothbrush' ]
29 |
--------------------------------------------------------------------------------
/yolov5-face/data/hyp.finetune.yaml:
--------------------------------------------------------------------------------
1 | # Hyperparameters for VOC finetuning
2 | # python train.py --batch 64 --weights yolov5m.pt --data voc.yaml --img 512 --epochs 50
3 | # See tutorials for hyperparameter evolution https://github.com/ultralytics/yolov5#tutorials
4 |
5 |
6 | # Hyperparameter Evolution Results
7 | # Generations: 306
8 | # P R mAP.5 mAP.5:.95 box obj cls
9 | # Metrics: 0.6 0.936 0.896 0.684 0.0115 0.00805 0.00146
10 |
11 | lr0: 0.0032
12 | lrf: 0.12
13 | momentum: 0.843
14 | weight_decay: 0.00036
15 | warmup_epochs: 2.0
16 | warmup_momentum: 0.5
17 | warmup_bias_lr: 0.05
18 | box: 0.0296
19 | cls: 0.243
20 | cls_pw: 0.631
21 | obj: 0.301
22 | obj_pw: 0.911
23 | iou_t: 0.2
24 | anchor_t: 2.91
25 | # anchors: 3.63
26 | fl_gamma: 0.0
27 | hsv_h: 0.0138
28 | hsv_s: 0.664
29 | hsv_v: 0.464
30 | degrees: 0.373
31 | translate: 0.245
32 | scale: 0.898
33 | shear: 0.602
34 | perspective: 0.0
35 | flipud: 0.00856
36 | fliplr: 0.5
37 | mosaic: 1.0
38 | mixup: 0.243
39 |
--------------------------------------------------------------------------------
/yolov5-face/data/hyp.scratch.yaml:
--------------------------------------------------------------------------------
1 | # Hyperparameters for COCO training from scratch
2 | # python train.py --batch 40 --cfg yolov5m.yaml --weights '' --data coco.yaml --img 640 --epochs 300
3 | # See tutorials for hyperparameter evolution https://github.com/ultralytics/yolov5#tutorials
4 |
5 |
6 | lr0: 0.01 # initial learning rate (SGD=1E-2, Adam=1E-3)
7 | lrf: 0.2 # final OneCycleLR learning rate (lr0 * lrf)
8 | momentum: 0.937 # SGD momentum/Adam beta1
9 | weight_decay: 0.0005 # optimizer weight decay 5e-4
10 | warmup_epochs: 3.0 # warmup epochs (fractions ok)
11 | warmup_momentum: 0.8 # warmup initial momentum
12 | warmup_bias_lr: 0.1 # warmup initial bias lr
13 | box: 0.05 # box loss gain
14 | cls: 0.5 # cls loss gain
15 | landmark: 0.005 # landmark loss gain
16 | cls_pw: 1.0 # cls BCELoss positive_weight
17 | obj: 1.0 # obj loss gain (scale with pixels)
18 | obj_pw: 1.0 # obj BCELoss positive_weight
19 | iou_t: 0.20 # IoU training threshold
20 | anchor_t: 4.0 # anchor-multiple threshold
21 | # anchors: 3 # anchors per output layer (0 to ignore)
22 | fl_gamma: 0.0 # focal loss gamma (efficientDet default gamma=1.5)
23 | hsv_h: 0.015 # image HSV-Hue augmentation (fraction)
24 | hsv_s: 0.7 # image HSV-Saturation augmentation (fraction)
25 | hsv_v: 0.4 # image HSV-Value augmentation (fraction)
26 | degrees: 0.0 # image rotation (+/- deg)
27 | translate: 0.1 # image translation (+/- fraction)
28 | scale: 0.5 # image scale (+/- gain)
29 | shear: 0.5 # image shear (+/- deg)
30 | perspective: 0.0 # image perspective (+/- fraction), range 0-0.001
31 | flipud: 0.0 # image flip up-down (probability)
32 | fliplr: 0.5 # image flip left-right (probability)
33 | mosaic: 0.5 # image mosaic (probability)
34 | mixup: 0.0 # image mixup (probability)
35 |
--------------------------------------------------------------------------------
/yolov5-face/data/hyp_1.yaml:
--------------------------------------------------------------------------------
1 | # Hyperparameters for COCO training from scratch
2 | # python train.py --batch 40 --cfg yolov5m.yaml --weights '' --data coco.yaml --img 640 --epochs 300
3 | # See tutorials for hyperparameter evolution https://github.com/ultralytics/yolov5#tutorials
4 |
5 |
6 | lr0: 0.01 # initial learning rate (SGD=1E-2, Adam=1E-3)
7 | lrf: 0.2 # final OneCycleLR learning rate (lr0 * lrf)
8 | momentum: 0.937 # SGD momentum/Adam beta1
9 | weight_decay: 0.0005 # optimizer weight decay 5e-4
10 | warmup_epochs: 3.0 # warmup epochs (fractions ok)
11 | warmup_momentum: 0.8 # warmup initial momentum
12 | warmup_bias_lr: 0.1 # warmup initial bias lr
13 | box: 0.05 # box loss gain
14 | cls: 0.5 # cls loss gain
15 | landmark: 0.005 # landmark loss gain
16 | cls_pw: 1.0 # cls BCELoss positive_weight
17 | obj: 1.0 # obj loss gain (scale with pixels)
18 | obj_pw: 1.0 # obj BCELoss positive_weight
19 | iou_t: 0.20 # IoU training threshold
20 | anchor_t: 4.0 # anchor-multiple threshold
21 | # anchors: 3 # anchors per output layer (0 to ignore)
22 | fl_gamma: 0.0 # focal loss gamma (efficientDet default gamma=1.5)
23 | hsv_h: 0.015 # image HSV-Hue augmentation (fraction)
24 | hsv_s: 0.7 # image HSV-Saturation augmentation (fraction)
25 | hsv_v: 0.4 # image HSV-Value augmentation (fraction)
26 | degrees: 0.1 # image rotation (+/- deg)
27 | translate: 0.1 # image translation (+/- fraction)
28 | scale: 0.5 # image scale (+/- gain)
29 | shear: 0.5 # image shear (+/- deg)
30 | perspective: 0.0 # image perspective (+/- fraction), range 0-0.001
31 | flipud: 0.0 # image flip up-down (probability)
32 | fliplr: 0.5 # image flip left-right (probability)
33 | mosaic: 1.0 # image mosaic (probability)
34 | mixup: 0.2 # image mixup (probability)
--------------------------------------------------------------------------------
/yolov5-face/data/retinaface2yolo.py:
--------------------------------------------------------------------------------
1 | import os
2 | import os.path
3 | import sys
4 | import torch
5 | import torch.utils.data as data
6 | import cv2
7 | import numpy as np
8 |
9 | class WiderFaceDetection(data.Dataset):
10 | def __init__(self, txt_path, preproc=None):
11 | self.preproc = preproc
12 | self.imgs_path = []
13 | self.words = []
14 | f = open(txt_path,'r')
15 | lines = f.readlines()
16 | isFirst = True
17 | labels = []
18 | for line in lines:
19 | line = line.rstrip()
20 | if line.startswith('#'):
21 | if isFirst is True:
22 | isFirst = False
23 | else:
24 | labels_copy = labels.copy()
25 | self.words.append(labels_copy)
26 | labels.clear()
27 | path = line[2:]
28 | path = txt_path.replace('label.txt','images/') + path
29 | self.imgs_path.append(path)
30 | else:
31 | line = line.split(' ')
32 | label = [float(x) for x in line]
33 | labels.append(label)
34 |
35 | self.words.append(labels)
36 |
37 | def __len__(self):
38 | return len(self.imgs_path)
39 |
40 | def __getitem__(self, index):
41 | img = cv2.imread(self.imgs_path[index])
42 | height, width, _ = img.shape
43 |
44 | labels = self.words[index]
45 | annotations = np.zeros((0, 15))
46 | if len(labels) == 0:
47 | return annotations
48 | for idx, label in enumerate(labels):
49 | annotation = np.zeros((1, 15))
50 | # bbox
51 | annotation[0, 0] = label[0] # x1
52 | annotation[0, 1] = label[1] # y1
53 | annotation[0, 2] = label[0] + label[2] # x2
54 | annotation[0, 3] = label[1] + label[3] # y2
55 |
56 | # landmarks
57 | annotation[0, 4] = label[4] # l0_x
58 | annotation[0, 5] = label[5] # l0_y
59 | annotation[0, 6] = label[7] # l1_x
60 | annotation[0, 7] = label[8] # l1_y
61 | annotation[0, 8] = label[10] # l2_x
62 | annotation[0, 9] = label[11] # l2_y
63 | annotation[0, 10] = label[13] # l3_x
64 | annotation[0, 11] = label[14] # l3_y
65 | annotation[0, 12] = label[16] # l4_x
66 | annotation[0, 13] = label[17] # l4_y
67 | if (annotation[0, 4]<0):
68 | annotation[0, 14] = -1
69 | else:
70 | annotation[0, 14] = 1
71 |
72 | annotations = np.append(annotations, annotation, axis=0)
73 | target = np.array(annotations)
74 | if self.preproc is not None:
75 | img, target = self.preproc(img, target)
76 |
77 | return torch.from_numpy(img), target
78 |
79 | def detection_collate(batch):
80 | """Custom collate fn for dealing with batches of images that have a different
81 | number of associated object annotations (bounding boxes).
82 |
83 | Arguments:
84 | batch: (tuple) A tuple of tensor images and lists of annotations
85 |
86 | Return:
87 | A tuple containing:
88 | 1) (tensor) batch of images stacked on their 0 dim
89 | 2) (list of tensors) annotations for a given image are stacked on 0 dim
90 | """
91 | targets = []
92 | imgs = []
93 | for _, sample in enumerate(batch):
94 | for _, tup in enumerate(sample):
95 | if torch.is_tensor(tup):
96 | imgs.append(tup)
97 | elif isinstance(tup, type(np.empty(0))):
98 | annos = torch.from_numpy(tup).float()
99 | targets.append(annos)
100 |
101 | return (torch.stack(imgs, 0), targets)
102 |
103 | save_path = '/ssd_1t/derron/yolov5-face/data/widerface/train'
104 | aa=WiderFaceDetection("/ssd_1t/derron/yolov5-face/data/widerface/widerface/train/label.txt")
105 | for i in range(len(aa.imgs_path)):
106 | print(i, aa.imgs_path[i])
107 | img = cv2.imread(aa.imgs_path[i])
108 | base_img = os.path.basename(aa.imgs_path[i])
109 | base_txt = os.path.basename(aa.imgs_path[i])[:-4] +".txt"
110 | save_img_path = os.path.join(save_path, base_img)
111 | save_txt_path = os.path.join(save_path, base_txt)
112 | with open(save_txt_path, "w") as f:
113 | height, width, _ = img.shape
114 | labels = aa.words[i]
115 | annotations = np.zeros((0, 14))
116 | if len(labels) == 0:
117 | continue
118 | for idx, label in enumerate(labels):
119 | annotation = np.zeros((1, 14))
120 | # bbox
121 | label[0] = max(0, label[0])
122 | label[1] = max(0, label[1])
123 | label[2] = min(width - 1, label[2])
124 | label[3] = min(height - 1, label[3])
125 | annotation[0, 0] = (label[0] + label[2] / 2) / width # cx
126 | annotation[0, 1] = (label[1] + label[3] / 2) / height # cy
127 | annotation[0, 2] = label[2] / width # w
128 | annotation[0, 3] = label[3] / height # h
129 | #if (label[2] -label[0]) < 8 or (label[3] - label[1]) < 8:
130 | # img[int(label[1]):int(label[3]), int(label[0]):int(label[2])] = 127
131 | # continue
132 | # landmarks
133 | annotation[0, 4] = label[4] / width # l0_x
134 | annotation[0, 5] = label[5] / height # l0_y
135 | annotation[0, 6] = label[7] / width # l1_x
136 | annotation[0, 7] = label[8] / height # l1_y
137 | annotation[0, 8] = label[10] / width # l2_x
138 | annotation[0, 9] = label[11] / height # l2_y
139 | annotation[0, 10] = label[13] / width # l3_x
140 | annotation[0, 11] = label[14] / height # l3_y
141 | annotation[0, 12] = label[16] / width # l4_x
142 | annotation[0, 13] = label[17] / height # l4_y
143 | str_label="0 "
144 | for i in range(len(annotation[0])):
145 | str_label =str_label+" "+str(annotation[0][i])
146 | str_label = str_label.replace('[', '').replace(']', '')
147 | str_label = str_label.replace(',', '') + '\n'
148 | f.write(str_label)
149 | cv2.imwrite(save_img_path, img)
150 |
151 |
--------------------------------------------------------------------------------
/yolov5-face/data/scripts/get_argoverse_hd.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Argoverse-HD dataset (ring-front-center camera) http://www.cs.cmu.edu/~mengtial/proj/streaming/
3 | # Download command: bash data/scripts/get_argoverse_hd.sh
4 | # Train command: python train.py --data argoverse_hd.yaml
5 | # Default dataset location is next to /yolov5:
6 | # /parent_folder
7 | # /argoverse
8 | # /yolov5
9 |
10 | # Download/unzip images
11 | d='../argoverse/' # unzip directory
12 | mkdir $d
13 | url=https://argoverse-hd.s3.us-east-2.amazonaws.com/
14 | f=Argoverse-HD-Full.zip
15 | curl -L $url$f -o $f && unzip -q $f -d $d && rm $f download, unzip, remove in background
16 | wait # finish background tasks
17 |
18 | cd ../argoverse/Argoverse-1.1/
19 | ln -s tracking images
20 |
21 | cd ../Argoverse-HD/annotations/
22 |
23 | python3 - "$@" <train.txt
91 | cat 2007_train.txt 2007_val.txt 2007_test.txt 2012_train.txt 2012_val.txt >train.all.txt
92 |
93 | python3 - "$@" <= 1
157 | p, im0, frame = path[i], im0s[i].copy(), dataset.count
158 | else:
159 | p, im0, frame = path, im0s.copy(), getattr(dataset, 'frame', 0)
160 |
161 | p = Path(p) # to Path
162 | save_path = str(Path(save_dir) / p.name) # im.jpg
163 |
164 | if len(det):
165 | # Rescale boxes from img_size to im0 size
166 | det[:, :4] = scale_coords(img.shape[2:], det[:, :4], im0.shape).round()
167 |
168 | # Print results
169 | for c in det[:, -1].unique():
170 | n = (det[:, -1] == c).sum() # detections per class
171 |
172 | det[:, 5:15] = scale_coords_landmarks(img.shape[2:], det[:, 5:15], im0.shape).round()
173 |
174 | for j in range(det.size()[0]):
175 | xyxy = det[j, :4].view(-1).tolist()
176 | conf = det[j, 4].cpu().numpy()
177 | landmarks = det[j, 5:15].view(-1).tolist()
178 | class_num = det[j, 15].cpu().numpy()
179 |
180 | im0 = show_results(im0, xyxy, conf, landmarks, class_num)
181 |
182 |
183 | cv2.imshow('result', im0)
184 | key = cv2.waitKey(0) & 0xFF
185 | if key == ord("q"):
186 | break
187 |
188 | # Save results (image with detections)
189 | if save_img:
190 | if dataset.mode == 'image':
191 | cv2.imwrite(save_path, im0)
192 | else: # 'video' or 'stream'
193 | if vid_path[i] != save_path: # new video
194 | vid_path[i] = save_path
195 | if isinstance(vid_writer[i], cv2.VideoWriter):
196 | vid_writer[i].release() # release previous video writer
197 | if vid_cap: # video
198 | fps = vid_cap.get(cv2.CAP_PROP_FPS)
199 | w = int(vid_cap.get(cv2.CAP_PROP_FRAME_WIDTH))
200 | h = int(vid_cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
201 | else: # stream
202 | fps, w, h = 30, im0.shape[1], im0.shape[0]
203 | save_path = str(Path(save_path).with_suffix('.mp4')) # force *.mp4 suffix on results videos
204 | vid_writer[i] = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*'mp4v'), fps, (w, h))
205 | try:
206 | vid_writer[i].write(im0)
207 | except Exception as e:
208 | print(e)
209 |
210 |
211 |
212 |
213 |
214 | if __name__ == '__main__':
215 | parser = argparse.ArgumentParser()
216 | parser.add_argument('--weights', nargs='+', type=str, default='runs/train/exp5/weights/last.pt', help='model.pt path(s)')
217 | parser.add_argument('--source', type=str, default='0', help='source') # file/folder, 0 for webcam
218 | parser.add_argument('--img-size', type=int, default=640, help='inference size (pixels)')
219 | parser.add_argument('--project', default=ROOT / 'runs/detect', help='save results to project/name')
220 | parser.add_argument('--name', default='exp', help='save results to project/name')
221 | parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment')
222 | parser.add_argument('--save-img', action='store_true', help='save results')
223 | parser.add_argument('--view-img', action='store_true', help='show results')
224 | opt = parser.parse_args()
225 |
226 | device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
227 | model = load_model(opt.weights, device)
228 | detect(model, opt.source, device, opt.img_size, opt.project, opt.name, opt.exist_ok, opt.save_img, opt.view_img)
229 |
--------------------------------------------------------------------------------
/yolov5-face/export.py:
--------------------------------------------------------------------------------
1 | """Exports a YOLOv5 *.pt model to ONNX and TorchScript formats
2 |
3 | Usage:
4 | $ export PYTHONPATH="$PWD" && python models/export.py --weights ./weights/yolov5s.pt --img 640 --batch 1
5 | """
6 |
7 | import argparse
8 | import sys
9 | import time
10 |
11 | sys.path.append('./') # to run '$ python *.py' files in subdirectories
12 |
13 | import torch
14 | import torch.nn as nn
15 |
16 | import models
17 | from models.experimental import attempt_load
18 | from utils.activations import Hardswish, SiLU
19 | from utils.general import set_logging, check_img_size
20 | import onnx
21 |
22 | if __name__ == '__main__':
23 | parser = argparse.ArgumentParser()
24 | parser.add_argument('--weights', type=str, default='./yolov5s.pt', help='weights path') # from yolov5/models/
25 | parser.add_argument('--img_size', nargs='+', type=int, default=[640, 640], help='image size') # height, width
26 | parser.add_argument('--batch_size', type=int, default=1, help='batch size')
27 | parser.add_argument('--simplify', action='store_true', default=False, help='simplify onnx')
28 | parser.add_argument('--dynamic', action='store_true', default=False, help='enable dynamic axis in onnx model')
29 | parser.add_argument('--onnx2pb', action='store_true', default=False, help='export onnx to pb')
30 | parser.add_argument('--onnx_infer', action='store_true', default=True, help='onnx infer test')
31 | #=======================TensorRT=================================
32 | parser.add_argument('--onnx2trt', action='store_true', default=False, help='export onnx to tensorrt')
33 | parser.add_argument('--fp16_trt', action='store_true', default=False, help='fp16 infer')
34 | #================================================================
35 | opt = parser.parse_args()
36 | opt.img_size *= 2 if len(opt.img_size) == 1 else 1 # expand
37 | print(opt)
38 | set_logging()
39 | t = time.time()
40 |
41 | # Load PyTorch model
42 | model = attempt_load(opt.weights, map_location=torch.device('cpu')) # load FP32 model
43 | delattr(model.model[-1], 'anchor_grid')
44 | model.model[-1].anchor_grid=[torch.zeros(1)] * 3 # nl=3 number of detection layers
45 | model.model[-1].export_cat = True
46 | model.eval()
47 | labels = model.names
48 |
49 | # Checks
50 | gs = int(max(model.stride)) # grid size (max stride)
51 | opt.img_size = [check_img_size(x, gs) for x in opt.img_size] # verify img_size are gs-multiples
52 |
53 | # Input
54 | img = torch.zeros(opt.batch_size, 3, *opt.img_size) # image size(1,3,320,192) iDetection
55 |
56 | # Update model
57 | for k, m in model.named_modules():
58 | m._non_persistent_buffers_set = set() # pytorch 1.6.0 compatibility
59 | if isinstance(m, models.common.Conv): # assign export-friendly activations
60 | if isinstance(m.act, nn.Hardswish):
61 | m.act = Hardswish()
62 | elif isinstance(m.act, nn.SiLU):
63 | m.act = SiLU()
64 | # elif isinstance(m, models.yolo.Detect):
65 | # m.forward = m.forward_export # assign forward (optional)
66 | if isinstance(m, models.common.ShuffleV2Block):#shufflenet block nn.SiLU
67 | for i in range(len(m.branch1)):
68 | if isinstance(m.branch1[i], nn.SiLU):
69 | m.branch1[i] = SiLU()
70 | for i in range(len(m.branch2)):
71 | if isinstance(m.branch2[i], nn.SiLU):
72 | m.branch2[i] = SiLU()
73 | y = model(img) # dry run
74 |
75 | # ONNX export
76 | print('\nStarting ONNX export with onnx %s...' % onnx.__version__)
77 | f = opt.weights.replace('.pt', '.onnx') # filename
78 | model.fuse() # only for ONNX
79 | input_names=['input']
80 | output_names=['output']
81 | torch.onnx.export(model, img, f, verbose=False, opset_version=12,
82 | input_names=input_names,
83 | output_names=output_names,
84 | dynamic_axes = {'input': {0: 'batch'},
85 | 'output': {0: 'batch'}
86 | } if opt.dynamic else None)
87 |
88 | # Checks
89 | onnx_model = onnx.load(f) # load onnx model
90 | onnx.checker.check_model(onnx_model) # check onnx model
91 |
92 | # https://github.com/daquexian/onnx-simplifier
93 | if opt.simplify:
94 | try:
95 | import onnxsim
96 | print(f'simplifying with onnx-simplifier {onnxsim.__version__}...')
97 | onnx_model, check = onnxsim.simplify(onnx_model,
98 | dynamic_input_shape=opt.dynamic,
99 | input_shapes={'input': list(img.shape)} if opt.dynamic else None)
100 | assert check, "simplify check failed "
101 | onnx.save(onnx_model, f)
102 | except Exception as e:
103 | print(f"simplifer failure: {e}")
104 |
105 | print('ONNX export success, saved as %s' % f)
106 | # Finish
107 | print('\nExport complete (%.2fs). Visualize with https://github.com/lutzroeder/netron.' % (time.time() - t))
108 |
109 |
110 | # onnx infer
111 | if opt.onnx_infer:
112 | import onnxruntime
113 | import numpy as np
114 | providers = ['CPUExecutionProvider']
115 | session = onnxruntime.InferenceSession(f, providers=providers)
116 | im = img.cpu().numpy().astype(np.float32) # torch to numpy
117 | y_onnx = session.run([session.get_outputs()[0].name], {session.get_inputs()[0].name: im})[0]
118 | print("pred's shape is ",y_onnx.shape)
119 | print("max(|torch_pred - onnx_pred|) =",abs(y.cpu().numpy()-y_onnx).max())
120 |
121 |
122 | # TensorRT export
123 | if opt.onnx2trt:
124 | from torch2trt.trt_model import ONNX_to_TRT
125 | print('\nStarting TensorRT...')
126 | ONNX_to_TRT(onnx_model_path=f,trt_engine_path=f.replace('.onnx', '.trt'),fp16_mode=opt.fp16_trt)
127 |
128 | # PB export
129 | if opt.onnx2pb:
130 | print('download the newest onnx_tf by https://github.com/onnx/onnx-tensorflow/tree/master/onnx_tf')
131 | from onnx_tf.backend import prepare
132 | import tensorflow as tf
133 |
134 | outpb = f.replace('.onnx', '.pb') # filename
135 | # strict=True maybe leads to KeyError: 'pyfunc_0', check: https://github.com/onnx/onnx-tensorflow/issues/167
136 | tf_rep = prepare(onnx_model, strict=False) # prepare tf representation
137 | tf_rep.export_graph(outpb) # export the model
138 |
139 | out_onnx = tf_rep.run(img) # onnx output
140 |
141 | # check pb
142 | with tf.Graph().as_default():
143 | graph_def = tf.GraphDef()
144 | with open(outpb, "rb") as f:
145 | graph_def.ParseFromString(f.read())
146 | tf.import_graph_def(graph_def, name="")
147 | with tf.Session() as sess:
148 | init = tf.global_variables_initializer()
149 | input_x = sess.graph.get_tensor_by_name(input_names[0]+':0') # input
150 | outputs = []
151 | for i in output_names:
152 | outputs.append(sess.graph.get_tensor_by_name(i+':0'))
153 | out_pb = sess.run(outputs, feed_dict={input_x: img})
154 |
155 | print(f'out_pytorch {y}')
156 | print(f'out_onnx {out_onnx}')
157 | print(f'out_pb {out_pb}')
158 |
--------------------------------------------------------------------------------
/yolov5-face/hubconf.py:
--------------------------------------------------------------------------------
1 | """File for accessing YOLOv5 via PyTorch Hub https://pytorch.org/hub/
2 |
3 | Usage:
4 | import torch
5 | model = torch.hub.load('ultralytics/yolov5', 'yolov5s', pretrained=True, channels=3, classes=80)
6 | """
7 |
8 | from pathlib import Path
9 |
10 | import torch
11 |
12 | from models.yolo import Model
13 | from utils.general import set_logging
14 | from utils.google_utils import attempt_download
15 |
16 | dependencies = ['torch', 'yaml']
17 | set_logging()
18 |
19 |
20 | def create(name, pretrained, channels, classes, autoshape):
21 | """Creates a specified YOLOv5 model
22 |
23 | Arguments:
24 | name (str): name of model, i.e. 'yolov5s'
25 | pretrained (bool): load pretrained weights into the model
26 | channels (int): number of input channels
27 | classes (int): number of model classes
28 |
29 | Returns:
30 | pytorch model
31 | """
32 | config = Path(__file__).parent / 'models' / f'{name}.yaml' # model.yaml path
33 | try:
34 | model = Model(config, channels, classes)
35 | if pretrained:
36 | fname = f'{name}.pt' # checkpoint filename
37 | attempt_download(fname) # download if not found locally
38 | ckpt = torch.load(fname, map_location=torch.device('cpu')) # load
39 | state_dict = ckpt['model'].float().state_dict() # to FP32
40 | state_dict = {k: v for k, v in state_dict.items() if model.state_dict()[k].shape == v.shape} # filter
41 | model.load_state_dict(state_dict, strict=False) # load
42 | if len(ckpt['model'].names) == classes:
43 | model.names = ckpt['model'].names # set class names attribute
44 | if autoshape:
45 | model = model.autoshape() # for file/URI/PIL/cv2/np inputs and NMS
46 | return model
47 |
48 | except Exception as e:
49 | help_url = 'https://github.com/ultralytics/yolov5/issues/36'
50 | s = 'Cache maybe be out of date, try force_reload=True. See %s for help.' % help_url
51 | raise Exception(s) from e
52 |
53 |
54 | def yolov5s(pretrained=False, channels=3, classes=80, autoshape=True):
55 | """YOLOv5-small model from https://github.com/ultralytics/yolov5
56 |
57 | Arguments:
58 | pretrained (bool): load pretrained weights into the model, default=False
59 | channels (int): number of input channels, default=3
60 | classes (int): number of model classes, default=80
61 |
62 | Returns:
63 | pytorch model
64 | """
65 | return create('yolov5s', pretrained, channels, classes, autoshape)
66 |
67 |
68 | def yolov5m(pretrained=False, channels=3, classes=80, autoshape=True):
69 | """YOLOv5-medium model from https://github.com/ultralytics/yolov5
70 |
71 | Arguments:
72 | pretrained (bool): load pretrained weights into the model, default=False
73 | channels (int): number of input channels, default=3
74 | classes (int): number of model classes, default=80
75 |
76 | Returns:
77 | pytorch model
78 | """
79 | return create('yolov5m', pretrained, channels, classes, autoshape)
80 |
81 |
82 | def yolov5l(pretrained=False, channels=3, classes=80, autoshape=True):
83 | """YOLOv5-large model from https://github.com/ultralytics/yolov5
84 |
85 | Arguments:
86 | pretrained (bool): load pretrained weights into the model, default=False
87 | channels (int): number of input channels, default=3
88 | classes (int): number of model classes, default=80
89 |
90 | Returns:
91 | pytorch model
92 | """
93 | return create('yolov5l', pretrained, channels, classes, autoshape)
94 |
95 |
96 | def yolov5x(pretrained=False, channels=3, classes=80, autoshape=True):
97 | """YOLOv5-xlarge model from https://github.com/ultralytics/yolov5
98 |
99 | Arguments:
100 | pretrained (bool): load pretrained weights into the model, default=False
101 | channels (int): number of input channels, default=3
102 | classes (int): number of model classes, default=80
103 |
104 | Returns:
105 | pytorch model
106 | """
107 | return create('yolov5x', pretrained, channels, classes, autoshape)
108 |
109 |
110 | def custom(path_or_model='path/to/model.pt', autoshape=True):
111 | """YOLOv5-custom model from https://github.com/ultralytics/yolov5
112 |
113 | Arguments (3 options):
114 | path_or_model (str): 'path/to/model.pt'
115 | path_or_model (dict): torch.load('path/to/model.pt')
116 | path_or_model (nn.Module): torch.load('path/to/model.pt')['model']
117 |
118 | Returns:
119 | pytorch model
120 | """
121 | model = torch.load(path_or_model) if isinstance(path_or_model, str) else path_or_model # load checkpoint
122 | if isinstance(model, dict):
123 | model = model['model'] # load model
124 |
125 | hub_model = Model(model.yaml).to(next(model.parameters()).device) # create
126 | hub_model.load_state_dict(model.float().state_dict()) # load state_dict
127 | hub_model.names = model.names # class names
128 | return hub_model.autoshape() if autoshape else hub_model
129 |
130 |
131 | if __name__ == '__main__':
132 | model = create(name='yolov5s', pretrained=True, channels=3, classes=80, autoshape=True) # pretrained example
133 | # model = custom(path_or_model='path/to/model.pt') # custom example
134 |
135 | # Verify inference
136 | from PIL import Image
137 |
138 | imgs = [Image.open(x) for x in Path('data/images').glob('*.jpg')]
139 | results = model(imgs)
140 | results.show()
141 | results.print()
142 |
--------------------------------------------------------------------------------
/yolov5-face/models/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IS2AI/AnyFace/bed844d23be03334f7fc12b2c4fb3ba2ac530bab/yolov5-face/models/__init__.py
--------------------------------------------------------------------------------
/yolov5-face/models/blazeface.yaml:
--------------------------------------------------------------------------------
1 | # parameters
2 | nc: 1 # number of classes
3 | depth_multiple: 1.0 # model depth multiple
4 | width_multiple: 1.0 # layer channel multiple
5 |
6 | # anchors
7 | anchors:
8 | - [5,6, 10,13, 21,26] # P3/8
9 | - [55,72, 225,304, 438,553] # P4/16
10 |
11 | # YOLOv5 backbone
12 | backbone:
13 | # [from, number, module, args]
14 | [[-1, 1, Conv, [24, 3, 2]], # 0-P1/2
15 | [-1, 2, BlazeBlock, [24]], # 1
16 | [-1, 1, BlazeBlock, [48, None, 2]], # 2-P2/4
17 | [-1, 2, BlazeBlock, [48]], # 3
18 | [-1, 1, DoubleBlazeBlock, [96, 24, 2]], # 4-P3/8
19 | [-1, 2, DoubleBlazeBlock, [96, 24]], # 5
20 | [-1, 1, DoubleBlazeBlock, [96, 24, 2]], # 6-P4/16
21 | [-1, 2, DoubleBlazeBlock, [96, 24]], # 7
22 | ]
23 |
24 |
25 | # YOLOv5 head
26 | head:
27 | [[-1, 1, Conv, [64, 1, 1]], # 8 (P4/32-large)
28 | [-1, 1, nn.Upsample, [None, 2, 'nearest']],
29 | [[-1, 5], 1, Concat, [1]], # cat backbone P3
30 | [-1, 1, Conv, [64, 1, 1]], # 11 (P3/8-medium)
31 |
32 | [[11, 8], 1, Detect, [nc, anchors]], # Detect(P3, P4)
33 | ]
34 |
--------------------------------------------------------------------------------
/yolov5-face/models/blazeface_fpn.yaml:
--------------------------------------------------------------------------------
1 | # parameters
2 | nc: 1 # number of classes
3 | depth_multiple: 1.0 # model depth multiple
4 | width_multiple: 1.0 # layer channel multiple
5 |
6 | # anchors
7 | anchors:
8 | - [5,6, 10,13, 21,26] # P3/8
9 | - [55,72, 225,304, 438,553] # P4/16
10 |
11 | # YOLOv5 backbone
12 | backbone:
13 | # [from, number, module, args]
14 | [[-1, 1, Conv, [24, 3, 2]], # 0-P1/2
15 | [-1, 2, BlazeBlock, [24]], # 1
16 | [-1, 1, BlazeBlock, [48, None, 2]], # 2-P2/4
17 | [-1, 2, BlazeBlock, [48]], # 3
18 | [-1, 1, DoubleBlazeBlock, [96, 24, 2]], # 4-P3/8
19 | [-1, 2, DoubleBlazeBlock, [96, 24]], # 5
20 | [-1, 1, DoubleBlazeBlock, [96, 24, 2]], # 6-P4/16
21 | [-1, 2, DoubleBlazeBlock, [96, 24]], # 7
22 | ]
23 |
24 |
25 | # YOLOv5 head
26 | head:
27 | [[-1, 1, Conv, [48, 1, 1]], # 8
28 | [-1, 1, nn.Upsample, [None, 2, 'nearest']],
29 | [[-1, 5], 1, Concat, [1]], # cat backbone P3
30 | [-1, 1, Conv, [48, 1, 1]], # 11 (P3/8-medium)
31 |
32 | [-1, 1, nn.MaxPool2d, [3, 2, 1]], # 12
33 | [[-1, 7], 1, Concat, [1]], # cat backbone P3
34 | [-1, 1, Conv, [48, 1, 1]], # 14 (P4/16-large)
35 |
36 | [[11, 14], 1, Detect, [nc, anchors]], # Detect(P3, P4)
37 | ]
38 |
39 |
--------------------------------------------------------------------------------
/yolov5-face/models/experimental.py:
--------------------------------------------------------------------------------
1 | # This file contains experimental modules
2 |
3 | import numpy as np
4 | import torch
5 | import torch.nn as nn
6 |
7 | from models.common import Conv, DWConv
8 | from utils.google_utils import attempt_download
9 |
10 |
11 | class CrossConv(nn.Module):
12 | # Cross Convolution Downsample
13 | def __init__(self, c1, c2, k=3, s=1, g=1, e=1.0, shortcut=False):
14 | # ch_in, ch_out, kernel, stride, groups, expansion, shortcut
15 | super(CrossConv, self).__init__()
16 | c_ = int(c2 * e) # hidden channels
17 | self.cv1 = Conv(c1, c_, (1, k), (1, s))
18 | self.cv2 = Conv(c_, c2, (k, 1), (s, 1), g=g)
19 | self.add = shortcut and c1 == c2
20 |
21 | def forward(self, x):
22 | return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x))
23 |
24 |
25 | class Sum(nn.Module):
26 | # Weighted sum of 2 or more layers https://arxiv.org/abs/1911.09070
27 | def __init__(self, n, weight=False): # n: number of inputs
28 | super(Sum, self).__init__()
29 | self.weight = weight # apply weights boolean
30 | self.iter = range(n - 1) # iter object
31 | if weight:
32 | self.w = nn.Parameter(-torch.arange(1., n) / 2, requires_grad=True) # layer weights
33 |
34 | def forward(self, x):
35 | y = x[0] # no weight
36 | if self.weight:
37 | w = torch.sigmoid(self.w) * 2
38 | for i in self.iter:
39 | y = y + x[i + 1] * w[i]
40 | else:
41 | for i in self.iter:
42 | y = y + x[i + 1]
43 | return y
44 |
45 |
46 | class GhostConv(nn.Module):
47 | # Ghost Convolution https://github.com/huawei-noah/ghostnet
48 | def __init__(self, c1, c2, k=1, s=1, g=1, act=True): # ch_in, ch_out, kernel, stride, groups
49 | super(GhostConv, self).__init__()
50 | c_ = c2 // 2 # hidden channels
51 | self.cv1 = Conv(c1, c_, k, s, None, g, act)
52 | self.cv2 = Conv(c_, c_, 5, 1, None, c_, act)
53 |
54 | def forward(self, x):
55 | y = self.cv1(x)
56 | return torch.cat([y, self.cv2(y)], 1)
57 |
58 |
59 | class GhostBottleneck(nn.Module):
60 | # Ghost Bottleneck https://github.com/huawei-noah/ghostnet
61 | def __init__(self, c1, c2, k, s):
62 | super(GhostBottleneck, self).__init__()
63 | c_ = c2 // 2
64 | self.conv = nn.Sequential(GhostConv(c1, c_, 1, 1), # pw
65 | DWConv(c_, c_, k, s, act=False) if s == 2 else nn.Identity(), # dw
66 | GhostConv(c_, c2, 1, 1, act=False)) # pw-linear
67 | self.shortcut = nn.Sequential(DWConv(c1, c1, k, s, act=False),
68 | Conv(c1, c2, 1, 1, act=False)) if s == 2 else nn.Identity()
69 |
70 | def forward(self, x):
71 | return self.conv(x) + self.shortcut(x)
72 |
73 |
74 | class MixConv2d(nn.Module):
75 | # Mixed Depthwise Conv https://arxiv.org/abs/1907.09595
76 | def __init__(self, c1, c2, k=(1, 3), s=1, equal_ch=True):
77 | super(MixConv2d, self).__init__()
78 | groups = len(k)
79 | if equal_ch: # equal c_ per group
80 | i = torch.linspace(0, groups - 1E-6, c2).floor() # c2 indices
81 | c_ = [(i == g).sum() for g in range(groups)] # intermediate channels
82 | else: # equal weight.numel() per group
83 | b = [c2] + [0] * groups
84 | a = np.eye(groups + 1, groups, k=-1)
85 | a -= np.roll(a, 1, axis=1)
86 | a *= np.array(k) ** 2
87 | a[0] = 1
88 | c_ = np.linalg.lstsq(a, b, rcond=None)[0].round() # solve for equal weight indices, ax = b
89 |
90 | self.m = nn.ModuleList([nn.Conv2d(c1, int(c_[g]), k[g], s, k[g] // 2, bias=False) for g in range(groups)])
91 | self.bn = nn.BatchNorm2d(c2)
92 | self.act = nn.LeakyReLU(0.1, inplace=True)
93 |
94 | def forward(self, x):
95 | return x + self.act(self.bn(torch.cat([m(x) for m in self.m], 1)))
96 |
97 |
98 | class Ensemble(nn.ModuleList):
99 | # Ensemble of models
100 | def __init__(self):
101 | super(Ensemble, self).__init__()
102 |
103 | def forward(self, x, augment=False):
104 | y = []
105 | for module in self:
106 | y.append(module(x, augment)[0])
107 | # y = torch.stack(y).max(0)[0] # max ensemble
108 | # y = torch.stack(y).mean(0) # mean ensemble
109 | y = torch.cat(y, 1) # nms ensemble
110 | return y, None # inference, train output
111 |
112 |
113 | def attempt_load(weights, map_location=None):
114 | # Loads an ensemble of models weights=[a,b,c] or a single model weights=[a] or weights=a
115 | model = Ensemble()
116 | for w in weights if isinstance(weights, list) else [weights]:
117 | attempt_download(w)
118 | model.append(torch.load(w, map_location=map_location)['model'].float().fuse().eval()) # load FP32 model
119 |
120 | # Compatibility updates
121 | for m in model.modules():
122 | if type(m) in [nn.Hardswish, nn.LeakyReLU, nn.ReLU, nn.ReLU6, nn.SiLU]:
123 | m.inplace = True # pytorch 1.7.0 compatibility
124 | elif type(m) is Conv:
125 | m._non_persistent_buffers_set = set() # pytorch 1.6.0 compatibility
126 |
127 | if len(model) == 1:
128 | return model[-1] # return model
129 | else:
130 | print('Ensemble created with %s\n' % weights)
131 | for k in ['names', 'stride']:
132 | setattr(model, k, getattr(model[-1], k))
133 | return model # return ensemble
134 |
--------------------------------------------------------------------------------
/yolov5-face/models/yolov5l.yaml:
--------------------------------------------------------------------------------
1 | # parameters
2 | nc: 1 # number of classes
3 | depth_multiple: 1.0 # model depth multiple
4 | width_multiple: 1.0 # layer channel multiple
5 |
6 | # anchors
7 | anchors:
8 | - [4,5, 8,10, 13,16] # P3/8
9 | - [23,29, 43,55, 73,105] # P4/16
10 | - [146,217, 231,300, 335,433] # P5/32
11 |
12 | # YOLOv5 backbone
13 | backbone:
14 | # [from, number, module, args]
15 | [[-1, 1, StemBlock, [64, 3, 2]], # 0-P1/2
16 | [-1, 3, C3, [128]],
17 | [-1, 1, Conv, [256, 3, 2]], # 2-P3/8
18 | [-1, 9, C3, [256]],
19 | [-1, 1, Conv, [512, 3, 2]], # 4-P4/16
20 | [-1, 9, C3, [512]],
21 | [-1, 1, Conv, [1024, 3, 2]], # 6-P5/32
22 | [-1, 1, SPP, [1024, [3,5,7]]],
23 | [-1, 3, C3, [1024, False]], # 8
24 | ]
25 |
26 | # YOLOv5 head
27 | head:
28 | [[-1, 1, Conv, [512, 1, 1]],
29 | [-1, 1, nn.Upsample, [None, 2, 'nearest']],
30 | [[-1, 5], 1, Concat, [1]], # cat backbone P4
31 | [-1, 3, C3, [512, False]], # 12
32 |
33 | [-1, 1, Conv, [256, 1, 1]],
34 | [-1, 1, nn.Upsample, [None, 2, 'nearest']],
35 | [[-1, 3], 1, Concat, [1]], # cat backbone P3
36 | [-1, 3, C3, [256, False]], # 16 (P3/8-small)
37 |
38 | [-1, 1, Conv, [256, 3, 2]],
39 | [[-1, 13], 1, Concat, [1]], # cat head P4
40 | [-1, 3, C3, [512, False]], # 19 (P4/16-medium)
41 |
42 | [-1, 1, Conv, [512, 3, 2]],
43 | [[-1, 9], 1, Concat, [1]], # cat head P5
44 | [-1, 3, C3, [1024, False]], # 22 (P5/32-large)
45 |
46 | [[16, 19, 22], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
47 | ]
48 |
--------------------------------------------------------------------------------
/yolov5-face/models/yolov5l6.yaml:
--------------------------------------------------------------------------------
1 | # parameters
2 | nc: 1 # number of classes
3 | depth_multiple: 1.0 # model depth multiple
4 | width_multiple: 1.0 # layer channel multiple
5 |
6 | # anchors
7 | anchors:
8 | - [6,7, 9,11, 13,16] # P3/8
9 | - [18,23, 26,33, 37,47] # P4/16
10 | - [54,67, 77,104, 112,154] # P5/32
11 | - [174,238, 258,355, 445,568] # P6/64
12 |
13 | # YOLOv5 backbone
14 | backbone:
15 | # [from, number, module, args]
16 | [ [ -1, 1, StemBlock, [ 64, 3, 2 ] ], # 0-P1/2
17 | [ -1, 3, C3, [ 128 ] ],
18 | [ -1, 1, Conv, [ 256, 3, 2 ] ], # 2-P3/8
19 | [ -1, 9, C3, [ 256 ] ],
20 | [ -1, 1, Conv, [ 512, 3, 2 ] ], # 4-P4/16
21 | [ -1, 9, C3, [ 512 ] ],
22 | [ -1, 1, Conv, [ 768, 3, 2 ] ], # 6-P5/32
23 | [ -1, 3, C3, [ 768 ] ],
24 | [ -1, 1, Conv, [ 1024, 3, 2 ] ], # 8-P6/64
25 | [ -1, 1, SPP, [ 1024, [ 3, 5, 7 ] ] ],
26 | [ -1, 3, C3, [ 1024, False ] ], # 10
27 | ]
28 |
29 | # YOLOv5 head
30 | head:
31 | [ [ -1, 1, Conv, [ 768, 1, 1 ] ],
32 | [ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ],
33 | [ [ -1, 7 ], 1, Concat, [ 1 ] ], # cat backbone P5
34 | [ -1, 3, C3, [ 768, False ] ], # 14
35 |
36 | [ -1, 1, Conv, [ 512, 1, 1 ] ],
37 | [ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ],
38 | [ [ -1, 5 ], 1, Concat, [ 1 ] ], # cat backbone P4
39 | [ -1, 3, C3, [ 512, False ] ], # 18
40 |
41 | [ -1, 1, Conv, [ 256, 1, 1 ] ],
42 | [ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ],
43 | [ [ -1, 3 ], 1, Concat, [ 1 ] ], # cat backbone P3
44 | [ -1, 3, C3, [ 256, False ] ], # 22 (P3/8-small)
45 |
46 | [ -1, 1, Conv, [ 256, 3, 2 ] ],
47 | [ [ -1, 19 ], 1, Concat, [ 1 ] ], # cat head P4
48 | [ -1, 3, C3, [ 512, False ] ], # 25 (P4/16-medium)
49 |
50 | [ -1, 1, Conv, [ 512, 3, 2 ] ],
51 | [ [ -1, 15 ], 1, Concat, [ 1 ] ], # cat head P5
52 | [ -1, 3, C3, [ 768, False ] ], # 28 (P5/32-large)
53 |
54 | [ -1, 1, Conv, [ 768, 3, 2 ] ],
55 | [ [ -1, 11 ], 1, Concat, [ 1 ] ], # cat head P6
56 | [ -1, 3, C3, [ 1024, False ] ], # 31 (P6/64-xlarge)
57 |
58 | [ [ 22, 25, 28, 31 ], 1, Detect, [ nc, anchors ] ], # Detect(P3, P4, P5, P6)
59 | ]
60 |
61 |
--------------------------------------------------------------------------------
/yolov5-face/models/yolov5m.yaml:
--------------------------------------------------------------------------------
1 | # parameters
2 | nc: 1 # number of classes
3 | depth_multiple: 0.67 # model depth multiple
4 | width_multiple: 0.75 # layer channel multiple
5 |
6 | # anchors
7 | anchors:
8 | - [4,5, 8,10, 13,16] # P3/8
9 | - [23,29, 43,55, 73,105] # P4/16
10 | - [146,217, 231,300, 335,433] # P5/32
11 |
12 | # YOLOv5 backbone
13 | backbone:
14 | # [from, number, module, args]
15 | [[-1, 1, StemBlock, [64, 3, 2]], # 0-P1/2
16 | [-1, 3, C3, [128]],
17 | [-1, 1, Conv, [256, 3, 2]], # 2-P3/8
18 | [-1, 9, C3, [256]],
19 | [-1, 1, Conv, [512, 3, 2]], # 4-P4/16
20 | [-1, 9, C3, [512]],
21 | [-1, 1, Conv, [1024, 3, 2]], # 6-P5/32
22 | [-1, 1, SPP, [1024, [3,5,7]]],
23 | [-1, 3, C3, [1024, False]], # 8
24 | ]
25 |
26 | # YOLOv5 head
27 | head:
28 | [[-1, 1, Conv, [512, 1, 1]],
29 | [-1, 1, nn.Upsample, [None, 2, 'nearest']],
30 | [[-1, 5], 1, Concat, [1]], # cat backbone P4
31 | [-1, 3, C3, [512, False]], # 12
32 |
33 | [-1, 1, Conv, [256, 1, 1]],
34 | [-1, 1, nn.Upsample, [None, 2, 'nearest']],
35 | [[-1, 3], 1, Concat, [1]], # cat backbone P3
36 | [-1, 3, C3, [256, False]], # 16 (P3/8-small)
37 |
38 | [-1, 1, Conv, [256, 3, 2]],
39 | [[-1, 13], 1, Concat, [1]], # cat head P4
40 | [-1, 3, C3, [512, False]], # 19 (P4/16-medium)
41 |
42 | [-1, 1, Conv, [512, 3, 2]],
43 | [[-1, 9], 1, Concat, [1]], # cat head P5
44 | [-1, 3, C3, [1024, False]], # 22 (P5/32-large)
45 |
46 | [[16, 19, 22], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
47 | ]
48 |
--------------------------------------------------------------------------------
/yolov5-face/models/yolov5m6.yaml:
--------------------------------------------------------------------------------
1 | # parameters
2 | nc: 1 # number of classes
3 | depth_multiple: 0.67 # model depth multiple
4 | width_multiple: 0.75 # layer channel multiple
5 |
6 | # anchors
7 | anchors:
8 | - [6,7, 9,11, 13,16] # P3/8
9 | - [18,23, 26,33, 37,47] # P4/16
10 | - [54,67, 77,104, 112,154] # P5/32
11 | - [174,238, 258,355, 445,568] # P6/64
12 |
13 | # YOLOv5 backbone
14 | backbone:
15 | # [from, number, module, args]
16 | [ [ -1, 1, StemBlock, [ 64, 3, 2 ] ], # 0-P1/2
17 | [ -1, 3, C3, [ 128 ] ],
18 | [ -1, 1, Conv, [ 256, 3, 2 ] ], # 2-P3/8
19 | [ -1, 9, C3, [ 256 ] ],
20 | [ -1, 1, Conv, [ 512, 3, 2 ] ], # 4-P4/16
21 | [ -1, 9, C3, [ 512 ] ],
22 | [ -1, 1, Conv, [ 768, 3, 2 ] ], # 6-P5/32
23 | [ -1, 3, C3, [ 768 ] ],
24 | [ -1, 1, Conv, [ 1024, 3, 2 ] ], # 8-P6/64
25 | [ -1, 1, SPP, [ 1024, [ 3, 5, 7 ] ] ],
26 | [ -1, 3, C3, [ 1024, False ] ], # 10
27 | ]
28 |
29 | # YOLOv5 head
30 | head:
31 | [ [ -1, 1, Conv, [ 768, 1, 1 ] ],
32 | [ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ],
33 | [ [ -1, 7 ], 1, Concat, [ 1 ] ], # cat backbone P5
34 | [ -1, 3, C3, [ 768, False ] ], # 14
35 |
36 | [ -1, 1, Conv, [ 512, 1, 1 ] ],
37 | [ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ],
38 | [ [ -1, 5 ], 1, Concat, [ 1 ] ], # cat backbone P4
39 | [ -1, 3, C3, [ 512, False ] ], # 18
40 |
41 | [ -1, 1, Conv, [ 256, 1, 1 ] ],
42 | [ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ],
43 | [ [ -1, 3 ], 1, Concat, [ 1 ] ], # cat backbone P3
44 | [ -1, 3, C3, [ 256, False ] ], # 22 (P3/8-small)
45 |
46 | [ -1, 1, Conv, [ 256, 3, 2 ] ],
47 | [ [ -1, 19 ], 1, Concat, [ 1 ] ], # cat head P4
48 | [ -1, 3, C3, [ 512, False ] ], # 25 (P4/16-medium)
49 |
50 | [ -1, 1, Conv, [ 512, 3, 2 ] ],
51 | [ [ -1, 15 ], 1, Concat, [ 1 ] ], # cat head P5
52 | [ -1, 3, C3, [ 768, False ] ], # 28 (P5/32-large)
53 |
54 | [ -1, 1, Conv, [ 768, 3, 2 ] ],
55 | [ [ -1, 11 ], 1, Concat, [ 1 ] ], # cat head P6
56 | [ -1, 3, C3, [ 1024, False ] ], # 31 (P6/64-xlarge)
57 |
58 | [ [ 22, 25, 28, 31 ], 1, Detect, [ nc, anchors ] ], # Detect(P3, P4, P5, P6)
59 | ]
60 |
61 |
--------------------------------------------------------------------------------
/yolov5-face/models/yolov5n-0.5.yaml:
--------------------------------------------------------------------------------
1 | # parameters
2 | nc: 1 # number of classes
3 | depth_multiple: 1.0 # model depth multiple
4 | width_multiple: 0.5 # layer channel multiple
5 |
6 | # anchors
7 | anchors:
8 | - [4,5, 8,10, 13,16] # P3/8
9 | - [23,29, 43,55, 73,105] # P4/16
10 | - [146,217, 231,300, 335,433] # P5/32
11 |
12 | # YOLOv5 backbone
13 | backbone:
14 | # [from, number, module, args]
15 | [[-1, 1, StemBlock, [32, 3, 2]], # 0-P2/4
16 | [-1, 1, ShuffleV2Block, [128, 2]], # 1-P3/8
17 | [-1, 3, ShuffleV2Block, [128, 1]], # 2
18 | [-1, 1, ShuffleV2Block, [256, 2]], # 3-P4/16
19 | [-1, 7, ShuffleV2Block, [256, 1]], # 4
20 | [-1, 1, ShuffleV2Block, [512, 2]], # 5-P5/32
21 | [-1, 3, ShuffleV2Block, [512, 1]], # 6
22 | ]
23 |
24 | # YOLOv5 head
25 | head:
26 | [[-1, 1, Conv, [128, 1, 1]],
27 | [-1, 1, nn.Upsample, [None, 2, 'nearest']],
28 | [[-1, 4], 1, Concat, [1]], # cat backbone P4
29 | [-1, 1, C3, [128, False]], # 10
30 |
31 | [-1, 1, Conv, [128, 1, 1]],
32 | [-1, 1, nn.Upsample, [None, 2, 'nearest']],
33 | [[-1, 2], 1, Concat, [1]], # cat backbone P3
34 | [-1, 1, C3, [128, False]], # 14 (P3/8-small)
35 |
36 | [-1, 1, Conv, [128, 3, 2]],
37 | [[-1, 11], 1, Concat, [1]], # cat head P4
38 | [-1, 1, C3, [128, False]], # 17 (P4/16-medium)
39 |
40 | [-1, 1, Conv, [128, 3, 2]],
41 | [[-1, 7], 1, Concat, [1]], # cat head P5
42 | [-1, 1, C3, [128, False]], # 20 (P5/32-large)
43 |
44 | [[14, 17, 20], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
45 | ]
46 |
47 |
--------------------------------------------------------------------------------
/yolov5-face/models/yolov5n.yaml:
--------------------------------------------------------------------------------
1 | # parameters
2 | nc: 1 # number of classes
3 | depth_multiple: 1.0 # model depth multiple
4 | width_multiple: 1.0 # layer channel multiple
5 |
6 | # anchors
7 | anchors:
8 | - [4,5, 8,10, 13,16] # P3/8
9 | - [23,29, 43,55, 73,105] # P4/16
10 | - [146,217, 231,300, 335,433] # P5/32
11 |
12 | # YOLOv5 backbone
13 | backbone:
14 | # [from, number, module, args]
15 | [[-1, 1, StemBlock, [32, 3, 2]], # 0-P2/4
16 | [-1, 1, ShuffleV2Block, [128, 2]], # 1-P3/8
17 | [-1, 3, ShuffleV2Block, [128, 1]], # 2
18 | [-1, 1, ShuffleV2Block, [256, 2]], # 3-P4/16
19 | [-1, 7, ShuffleV2Block, [256, 1]], # 4
20 | [-1, 1, ShuffleV2Block, [512, 2]], # 5-P5/32
21 | [-1, 3, ShuffleV2Block, [512, 1]], # 6
22 | ]
23 |
24 | # YOLOv5 head
25 | head:
26 | [[-1, 1, Conv, [128, 1, 1]],
27 | [-1, 1, nn.Upsample, [None, 2, 'nearest']],
28 | [[-1, 4], 1, Concat, [1]], # cat backbone P4
29 | [-1, 1, C3, [128, False]], # 10
30 |
31 | [-1, 1, Conv, [128, 1, 1]],
32 | [-1, 1, nn.Upsample, [None, 2, 'nearest']],
33 | [[-1, 2], 1, Concat, [1]], # cat backbone P3
34 | [-1, 1, C3, [128, False]], # 14 (P3/8-small)
35 |
36 | [-1, 1, Conv, [128, 3, 2]],
37 | [[-1, 11], 1, Concat, [1]], # cat head P4
38 | [-1, 1, C3, [128, False]], # 17 (P4/16-medium)
39 |
40 | [-1, 1, Conv, [128, 3, 2]],
41 | [[-1, 7], 1, Concat, [1]], # cat head P5
42 | [-1, 1, C3, [128, False]], # 20 (P5/32-large)
43 |
44 | [[14, 17, 20], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
45 | ]
46 |
47 |
--------------------------------------------------------------------------------
/yolov5-face/models/yolov5n6.yaml:
--------------------------------------------------------------------------------
1 | # parameters
2 | nc: 1 # number of classes
3 | depth_multiple: 1.0 # model depth multiple
4 | width_multiple: 1.0 # layer channel multiple
5 |
6 | # anchors
7 | anchors:
8 | - [6,7, 9,11, 13,16] # P3/8
9 | - [18,23, 26,33, 37,47] # P4/16
10 | - [54,67, 77,104, 112,154] # P5/32
11 | - [174,238, 258,355, 445,568] # P6/64
12 |
13 | # YOLOv5 backbone
14 | backbone:
15 | # [from, number, module, args]
16 | [[-1, 1, StemBlock, [32, 3, 2]], # 0-P2/4
17 | [-1, 1, ShuffleV2Block, [128, 2]], # 1-P3/8
18 | [-1, 3, ShuffleV2Block, [128, 1]], # 2
19 | [-1, 1, ShuffleV2Block, [256, 2]], # 3-P4/16
20 | [-1, 7, ShuffleV2Block, [256, 1]], # 4
21 | [-1, 1, ShuffleV2Block, [384, 2]], # 5-P5/32
22 | [-1, 3, ShuffleV2Block, [384, 1]], # 6
23 | [-1, 1, ShuffleV2Block, [512, 2]], # 7-P6/64
24 | [-1, 3, ShuffleV2Block, [512, 1]], # 8
25 | ]
26 |
27 | # YOLOv5 head
28 | head:
29 | [[-1, 1, Conv, [128, 1, 1]],
30 | [-1, 1, nn.Upsample, [None, 2, 'nearest']],
31 | [[-1, 6], 1, Concat, [1]], # cat backbone P5
32 | [-1, 1, C3, [128, False]], # 12
33 |
34 | [-1, 1, Conv, [128, 1, 1]],
35 | [-1, 1, nn.Upsample, [None, 2, 'nearest']],
36 | [[-1, 4], 1, Concat, [1]], # cat backbone P4
37 | [-1, 1, C3, [128, False]], # 16 (P4/8-small)
38 |
39 | [-1, 1, Conv, [128, 1, 1]],
40 | [-1, 1, nn.Upsample, [None, 2, 'nearest']],
41 | [[-1, 2], 1, Concat, [1]], # cat backbone P3
42 | [-1, 1, C3, [128, False]], # 20 (P3/8-small)
43 |
44 | [-1, 1, Conv, [128, 3, 2]],
45 | [[-1, 17], 1, Concat, [1]], # cat head P4
46 | [-1, 1, C3, [128, False]], # 23 (P4/16-medium)
47 |
48 | [-1, 1, Conv, [128, 3, 2]],
49 | [[-1, 13], 1, Concat, [1]], # cat head P5
50 | [-1, 1, C3, [128, False]], # 26 (P5/32-large)
51 |
52 | [-1, 1, Conv, [128, 3, 2]],
53 | [[-1, 9], 1, Concat, [1]], # cat head P6
54 | [-1, 1, C3, [128, False]], # 29 (P6/64-large)
55 |
56 | [[20, 23, 26, 29], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
57 | ]
58 |
59 |
--------------------------------------------------------------------------------
/yolov5-face/models/yolov5s.yaml:
--------------------------------------------------------------------------------
1 | # parameters
2 | nc: 1 # number of classes
3 | depth_multiple: 0.33 # model depth multiple
4 | width_multiple: 0.5 # layer channel multiple
5 |
6 | # anchors
7 | anchors:
8 | - [4,5, 8,10, 13,16] # P3/8
9 | - [23,29, 43,55, 73,105] # P4/16
10 | - [146,217, 231,300, 335,433] # P5/32
11 |
12 | # YOLOv5 backbone
13 | backbone:
14 | # [from, number, module, args]
15 | [[-1, 1, StemBlock, [64, 3, 2]], # 0-P1/2
16 | [-1, 3, C3, [128]],
17 | [-1, 1, Conv, [256, 3, 2]], # 2-P3/8
18 | [-1, 9, C3, [256]],
19 | [-1, 1, Conv, [512, 3, 2]], # 4-P4/16
20 | [-1, 9, C3, [512]],
21 | [-1, 1, Conv, [1024, 3, 2]], # 6-P5/32
22 | [-1, 1, SPP, [1024, [3,5,7]]],
23 | [-1, 3, C3, [1024, False]], # 8
24 | ]
25 |
26 | # YOLOv5 head
27 | head:
28 | [[-1, 1, Conv, [512, 1, 1]],
29 | [-1, 1, nn.Upsample, [None, 2, 'nearest']],
30 | [[-1, 5], 1, Concat, [1]], # cat backbone P4
31 | [-1, 3, C3, [512, False]], # 12
32 |
33 | [-1, 1, Conv, [256, 1, 1]],
34 | [-1, 1, nn.Upsample, [None, 2, 'nearest']],
35 | [[-1, 3], 1, Concat, [1]], # cat backbone P3
36 | [-1, 3, C3, [256, False]], # 16 (P3/8-small)
37 |
38 | [-1, 1, Conv, [256, 3, 2]],
39 | [[-1, 13], 1, Concat, [1]], # cat head P4
40 | [-1, 3, C3, [512, False]], # 19 (P4/16-medium)
41 |
42 | [-1, 1, Conv, [512, 3, 2]],
43 | [[-1, 9], 1, Concat, [1]], # cat head P5
44 | [-1, 3, C3, [1024, False]], # 22 (P5/32-large)
45 |
46 | [[16, 19, 22], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5)
47 | ]
48 |
--------------------------------------------------------------------------------
/yolov5-face/models/yolov5s6.yaml:
--------------------------------------------------------------------------------
1 | # parameters
2 | nc: 1 # number of classes
3 | depth_multiple: 0.33 # model depth multiple
4 | width_multiple: 0.50 # layer channel multiple
5 |
6 | # anchors
7 | anchors:
8 | - [6,7, 9,11, 13,16] # P3/8
9 | - [18,23, 26,33, 37,47] # P4/16
10 | - [54,67, 77,104, 112,154] # P5/32
11 | - [174,238, 258,355, 445,568] # P6/64
12 |
13 | # YOLOv5 backbone
14 | backbone:
15 | # [from, number, module, args]
16 | [ [ -1, 1, StemBlock, [ 64, 3, 2 ] ], # 0-P1/2
17 | [ -1, 3, C3, [ 128 ] ],
18 | [ -1, 1, Conv, [ 256, 3, 2 ] ], # 2-P3/8
19 | [ -1, 9, C3, [ 256 ] ],
20 | [ -1, 1, Conv, [ 512, 3, 2 ] ], # 4-P4/16
21 | [ -1, 9, C3, [ 512 ] ],
22 | [ -1, 1, Conv, [ 768, 3, 2 ] ], # 6-P5/32
23 | [ -1, 3, C3, [ 768 ] ],
24 | [ -1, 1, Conv, [ 1024, 3, 2 ] ], # 8-P6/64
25 | [ -1, 1, SPP, [ 1024, [ 3, 5, 7 ] ] ],
26 | [ -1, 3, C3, [ 1024, False ] ], # 10
27 | ]
28 |
29 | # YOLOv5 head
30 | head:
31 | [ [ -1, 1, Conv, [ 768, 1, 1 ] ],
32 | [ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ],
33 | [ [ -1, 7 ], 1, Concat, [ 1 ] ], # cat backbone P5
34 | [ -1, 3, C3, [ 768, False ] ], # 14
35 |
36 | [ -1, 1, Conv, [ 512, 1, 1 ] ],
37 | [ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ],
38 | [ [ -1, 5 ], 1, Concat, [ 1 ] ], # cat backbone P4
39 | [ -1, 3, C3, [ 512, False ] ], # 18
40 |
41 | [ -1, 1, Conv, [ 256, 1, 1 ] ],
42 | [ -1, 1, nn.Upsample, [ None, 2, 'nearest' ] ],
43 | [ [ -1, 3 ], 1, Concat, [ 1 ] ], # cat backbone P3
44 | [ -1, 3, C3, [ 256, False ] ], # 22 (P3/8-small)
45 |
46 | [ -1, 1, Conv, [ 256, 3, 2 ] ],
47 | [ [ -1, 19 ], 1, Concat, [ 1 ] ], # cat head P4
48 | [ -1, 3, C3, [ 512, False ] ], # 25 (P4/16-medium)
49 |
50 | [ -1, 1, Conv, [ 512, 3, 2 ] ],
51 | [ [ -1, 15 ], 1, Concat, [ 1 ] ], # cat head P5
52 | [ -1, 3, C3, [ 768, False ] ], # 28 (P5/32-large)
53 |
54 | [ -1, 1, Conv, [ 768, 3, 2 ] ],
55 | [ [ -1, 11 ], 1, Concat, [ 1 ] ], # cat head P6
56 | [ -1, 3, C3, [ 1024, False ] ], # 31 (P6/64-xlarge)
57 |
58 | [ [ 22, 25, 28, 31 ], 1, Detect, [ nc, anchors ] ], # Detect(P3, P4, P5, P6)
59 | ]
60 |
61 |
--------------------------------------------------------------------------------
/yolov5-face/test_widerface.py:
--------------------------------------------------------------------------------
1 | import argparse
2 | import glob
3 | import time
4 | from pathlib import Path
5 | from imutils import paths
6 |
7 | import os
8 | import cv2
9 | import torch
10 | import torch.backends.cudnn as cudnn
11 | from numpy import random
12 | import numpy as np
13 | from models.experimental import attempt_load
14 | from utils.datasets import letterbox
15 | from utils.general import check_img_size, check_requirements, non_max_suppression_face, apply_classifier, \
16 | scale_coords, xyxy2xywh, strip_optimizer, set_logging, increment_path
17 | from utils.plots import plot_one_box
18 | from utils.torch_utils import select_device, load_classifier, time_synchronized
19 | from tqdm import tqdm
20 |
21 | def dynamic_resize(shape, stride=64):
22 | max_size = max(shape[0], shape[1])
23 | if max_size % stride != 0:
24 | max_size = (int(max_size / stride) + 1) * stride
25 | return max_size
26 |
27 | def scale_coords_landmarks(img1_shape, coords, img0_shape, ratio_pad=None):
28 | # Rescale coords (xyxy) from img1_shape to img0_shape
29 | if ratio_pad is None: # calculate from img0_shape
30 | gain = min(img1_shape[0] / img0_shape[0], img1_shape[1] / img0_shape[1]) # gain = old / new
31 | pad = (img1_shape[1] - img0_shape[1] * gain) / 2, (img1_shape[0] - img0_shape[0] * gain) / 2 # wh padding
32 | else:
33 | gain = ratio_pad[0][0]
34 | pad = ratio_pad[1]
35 |
36 | coords[:, [0, 2, 4, 6, 8]] -= pad[0] # x padding
37 | coords[:, [1, 3, 5, 7, 9]] -= pad[1] # y padding
38 | coords[:, :10] /= gain
39 | #clip_coords(coords, img0_shape)
40 | coords[:, 0].clamp_(0, img0_shape[1]) # x1
41 | coords[:, 1].clamp_(0, img0_shape[0]) # y1
42 | coords[:, 2].clamp_(0, img0_shape[1]) # x2
43 | coords[:, 3].clamp_(0, img0_shape[0]) # y2
44 | coords[:, 4].clamp_(0, img0_shape[1]) # x3
45 | coords[:, 5].clamp_(0, img0_shape[0]) # y3
46 | coords[:, 6].clamp_(0, img0_shape[1]) # x4
47 | coords[:, 7].clamp_(0, img0_shape[0]) # y4
48 | coords[:, 8].clamp_(0, img0_shape[1]) # x5
49 | coords[:, 9].clamp_(0, img0_shape[0]) # y5
50 | return coords
51 |
52 | def show_results(img, xywh, conf, landmarks, class_num):
53 | h,w,c = img.shape
54 | tl = 1 or round(0.002 * (h + w) / 2) + 1 # line/font thickness
55 | x1 = int(xywh[0] * w - 0.5 * xywh[2] * w)
56 | y1 = int(xywh[1] * h - 0.5 * xywh[3] * h)
57 | x2 = int(xywh[0] * w + 0.5 * xywh[2] * w)
58 | y2 = int(xywh[1] * h + 0.5 * xywh[3] * h)
59 | cv2.rectangle(img, (x1,y1), (x2, y2), (0,255,0), thickness=tl, lineType=cv2.LINE_AA)
60 |
61 | clors = [(255,0,0),(0,255,0),(0,0,255),(255,255,0),(0,255,255)]
62 |
63 | for i in range(5):
64 | point_x = int(landmarks[2 * i] * w)
65 | point_y = int(landmarks[2 * i + 1] * h)
66 | cv2.circle(img, (point_x, point_y), tl+1, clors[i], -1)
67 |
68 | tf = max(tl - 1, 1) # font thickness
69 | label = str(int(class_num)) + ': ' + str(conf)[:5]
70 | cv2.putText(img, label, (x1, y1 - 2), 0, tl / 3, [225, 255, 255], thickness=tf, lineType=cv2.LINE_AA)
71 | return img
72 |
73 | def detect(model, img0):
74 | stride = int(model.stride.max()) # model stride
75 | imgsz = opt.img_size
76 | if imgsz <= 0: # original size
77 | imgsz = dynamic_resize(img0.shape)
78 | imgsz = check_img_size(imgsz, s=64) # check img_size
79 | img = letterbox(img0, imgsz)[0]
80 | # Convert
81 | img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x416x416
82 | img = np.ascontiguousarray(img)
83 | img = torch.from_numpy(img).to(device)
84 | img = img.float() # uint8 to fp16/32
85 | img /= 255.0 # 0 - 255 to 0.0 - 1.0
86 | if img.ndimension() == 3:
87 | img = img.unsqueeze(0)
88 |
89 | # Inference
90 | pred = model(img, augment=opt.augment)[0]
91 | # Apply NMS
92 | pred = non_max_suppression_face(pred, opt.conf_thres, opt.iou_thres)[0]
93 | gn = torch.tensor(img0.shape)[[1, 0, 1, 0]].to(device) # normalization gain whwh
94 | gn_lks = torch.tensor(img0.shape)[[1, 0, 1, 0, 1, 0, 1, 0, 1, 0]].to(device) # normalization gain landmarks
95 | boxes = []
96 | h, w, c = img0.shape
97 | if pred is not None:
98 | pred[:, :4] = scale_coords(img.shape[2:], pred[:, :4], img0.shape).round()
99 | pred[:, 5:15] = scale_coords_landmarks(img.shape[2:], pred[:, 5:15], img0.shape).round()
100 | for j in range(pred.size()[0]):
101 | xywh = (xyxy2xywh(pred[j, :4].view(1, 4)) / gn).view(-1)
102 | xywh = xywh.data.cpu().numpy()
103 | conf = pred[j, 4].cpu().numpy()
104 | landmarks = (pred[j, 5:15].view(1, 10) / gn_lks).view(-1).tolist()
105 | class_num = pred[j, 15].cpu().numpy()
106 | x1 = int(xywh[0] * w - 0.5 * xywh[2] * w)
107 | y1 = int(xywh[1] * h - 0.5 * xywh[3] * h)
108 | x2 = int(xywh[0] * w + 0.5 * xywh[2] * w)
109 | y2 = int(xywh[1] * h + 0.5 * xywh[3] * h)
110 | boxes.append([x1, y1, x2-x1, y2-y1, conf])
111 | return boxes
112 |
113 |
114 | # +
115 | if __name__ == '__main__':
116 | parser = argparse.ArgumentParser()
117 | parser.add_argument('--weights', nargs='+', type=str, default='runs/train/exp5/weights/last.pt', help='model.pt path(s)')
118 | parser.add_argument('--img-size', type=int, default=640, help='inference size (pixels)')
119 | parser.add_argument('--conf-thres', type=float, default=0.02, help='object confidence threshold')
120 | parser.add_argument('--iou-thres', type=float, default=0.5, help='IOU threshold for NMS')
121 | parser.add_argument('--device', default='0', help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
122 | parser.add_argument('--agnostic-nms', action='store_true', help='class-agnostic NMS')
123 | parser.add_argument('--augment', action='store_true', help='augmented inference')
124 | parser.add_argument('--update', action='store_true', help='update all models')
125 | parser.add_argument('--classes', nargs='+', type=int, help='filter by class: --class 0, or --class 0 2 3')
126 | parser.add_argument('--project', default='runs/detect', help='save results to project/name')
127 | parser.add_argument('--name', default='exp', help='save results to project/name')
128 | parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment')
129 | parser.add_argument('--save_folder', default='./widerface_evaluate/widerface_txt/', type=str, help='Dir to save txt results')
130 | parser.add_argument('--dataset_folder', default='../WiderFace/val/images/', type=str, help='dataset path')
131 | parser.add_argument('--folder_pict', default='/yolov5-face/data/widerface/val/wider_val.txt', type=str, help='folder_pict')
132 | opt = parser.parse_args()
133 | print(opt)
134 |
135 | # changhy : read folder_pict
136 | pict_folder = {}
137 | with open(opt.folder_pict, 'r') as f:
138 | lines = f.readlines()
139 | for line in lines:
140 | line = line.strip().split('/')
141 | pict_folder[line[-1]] = line[-2]
142 |
143 | # Load model
144 | device = select_device(opt.device)
145 | model = attempt_load(opt.weights, map_location=device) # load FP32 model
146 | with torch.no_grad():
147 | # testing dataset
148 | testset_folder = opt.dataset_folder
149 |
150 | # for image_path in tqdm(glob.glob(os.path.join(testset_folder, '*'))):
151 | for image_path in tqdm(paths.list_files(testset_folder, validExts="jpg")):
152 | if image_path.endswith('.txt'):
153 | continue
154 | img0 = cv2.imread(image_path) # BGR
155 | if img0 is None:
156 | print(f'ignore : {image_path}')
157 | continue
158 | boxes = detect(model, img0)
159 | # --------------------------------------------------------------------
160 | image_name = os.path.basename(image_path)
161 | txt_name = os.path.splitext(image_name)[0] + ".txt"
162 | save_name = os.path.join(opt.save_folder, pict_folder[image_name], txt_name)
163 | dirname = os.path.dirname(save_name)
164 | if not os.path.isdir(dirname):
165 | os.makedirs(dirname)
166 | with open(save_name, "w") as fd:
167 | file_name = os.path.basename(save_name)[:-4] + "\n"
168 | bboxs_num = str(len(boxes)) + "\n"
169 | fd.write(file_name)
170 | fd.write(bboxs_num)
171 | for box in boxes:
172 | fd.write('%d %d %d %d %.03f' % (box[0], box[1], box[2], box[3], box[4] if box[4] <= 1 else 1) + '\n')
173 | print('done.')
174 |
--------------------------------------------------------------------------------
/yolov5-face/torch2trt/imgs/yolov5l-face.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IS2AI/AnyFace/bed844d23be03334f7fc12b2c4fb3ba2ac530bab/yolov5-face/torch2trt/imgs/yolov5l-face.jpg
--------------------------------------------------------------------------------
/yolov5-face/torch2trt/imgs/yolov5m-face.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IS2AI/AnyFace/bed844d23be03334f7fc12b2c4fb3ba2ac530bab/yolov5-face/torch2trt/imgs/yolov5m-face.jpg
--------------------------------------------------------------------------------
/yolov5-face/torch2trt/imgs/yolov5n-0.5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IS2AI/AnyFace/bed844d23be03334f7fc12b2c4fb3ba2ac530bab/yolov5-face/torch2trt/imgs/yolov5n-0.5.jpg
--------------------------------------------------------------------------------
/yolov5-face/torch2trt/imgs/yolov5n-face.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IS2AI/AnyFace/bed844d23be03334f7fc12b2c4fb3ba2ac530bab/yolov5-face/torch2trt/imgs/yolov5n-face.jpg
--------------------------------------------------------------------------------
/yolov5-face/torch2trt/imgs/yolov5s-face.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IS2AI/AnyFace/bed844d23be03334f7fc12b2c4fb3ba2ac530bab/yolov5-face/torch2trt/imgs/yolov5s-face.jpg
--------------------------------------------------------------------------------
/yolov5-face/torch2trt/main.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 | import cv2
4 | import copy
5 | import torch
6 | import argparse
7 | root_path=os.path.dirname(os.path.abspath(os.path.dirname(__file__))) # 项目根路径:获取当前路径,再上级路径
8 | sys.path.append(root_path) # 将项目根路径写入系统路径
9 | from utils.general import check_img_size,non_max_suppression_face,scale_coords,xyxy2xywh
10 | from utils.datasets import letterbox
11 | from detect_face import scale_coords_landmarks,show_results
12 | from torch2trt.trt_model import TrtModel
13 | cur_path=os.path.abspath(os.path.dirname(__file__))
14 | def img_process(img_path,long_side=640,stride_max=32):
15 | '''
16 | 图像预处理
17 | '''
18 | orgimg=cv2.imread(img_path)
19 | img0 = copy.deepcopy(orgimg)
20 | h0, w0 = orgimg.shape[:2] # orig hw
21 | r = long_side/ max(h0, w0) # resize image to img_size
22 | if r != 1: # always resize down, only resize up if training with augmentation
23 | interp = cv2.INTER_AREA if r < 1 else cv2.INTER_LINEAR
24 | img0 = cv2.resize(img0, (int(w0 * r), int(h0 * r)), interpolation=interp)
25 |
26 | imgsz = check_img_size(long_side, s=stride_max) # check img_size
27 |
28 | img = letterbox(img0, new_shape=imgsz,auto=False)[0] # auto True最小矩形 False固定尺度
29 | # Convert
30 | img = img[:, :, ::-1].transpose(2, 0, 1).copy() # BGR to RGB, to 3x416x416
31 | img = torch.from_numpy(img)
32 | img = img.float() # uint8 to fp16/32
33 | img /= 255.0 # 0 - 255 to 0.0 - 1.0
34 | if img.ndimension() == 3:
35 | img = img.unsqueeze(0)
36 | return img,orgimg
37 |
38 | def img_vis(img,orgimg,pred,vis_thres = 0.6):
39 | '''
40 | 预测可视化
41 | vis_thres: 可视化阈值
42 | '''
43 |
44 | print('img.shape: ', img.shape)
45 | print('orgimg.shape: ', orgimg.shape)
46 |
47 | no_vis_nums=0
48 | # Process detections
49 | for i, det in enumerate(pred): # detections per image
50 | gn = torch.tensor(orgimg.shape)[[1, 0, 1, 0]] # normalization gain whwh
51 | gn_lks = torch.tensor(orgimg.shape)[[1, 0, 1, 0, 1, 0, 1, 0, 1, 0]] # normalization gain landmarks
52 | if len(det):
53 | # Rescale boxes from img_size to im0 size
54 | det[:, :4] = scale_coords(img.shape[2:], det[:, :4], orgimg.shape).round()
55 |
56 | # Print results
57 | for c in det[:, -1].unique():
58 | n = (det[:, -1] == c).sum() # detections per class
59 |
60 | det[:, 5:15] = scale_coords_landmarks(img.shape[2:], det[:, 5:15], orgimg.shape).round()
61 |
62 | for j in range(det.size()[0]):
63 |
64 |
65 | if det[j, 4].cpu().numpy() < vis_thres:
66 | no_vis_nums+=1
67 | continue
68 |
69 | xywh = (xyxy2xywh(det[j, :4].view(1, 4)) / gn).view(-1).tolist()
70 | conf = det[j, 4].cpu().numpy()
71 | landmarks = (det[j, 5:15].view(1, 10) / gn_lks).view(-1).tolist()
72 | class_num = det[j, 15].cpu().numpy()
73 | orgimg = show_results(orgimg, xywh, conf, landmarks, class_num)
74 |
75 | cv2.imwrite(cur_path+'/result.jpg', orgimg)
76 | print('result save in '+cur_path+'/result.jpg')
77 |
78 |
79 | if __name__ == '__main__':
80 | parser = argparse.ArgumentParser()
81 | parser.add_argument('--img_path', type=str, default=cur_path+"/sample.jpg", help='img path')
82 | parser.add_argument('--trt_path', type=str, required=True, help='trt_path')
83 | parser.add_argument('--output_shape', type=list, default=[1,25200,16], help='input[1,3,640,640] -> output[1,25200,16]')
84 | opt = parser.parse_args()
85 |
86 |
87 | img,orgimg=img_process(opt.img_path)
88 | model=TrtModel(opt.trt_path)
89 | pred=model(img.numpy()).reshape(opt.output_shape) # forward
90 | model.destroy()
91 |
92 | # Apply NMS
93 | pred = non_max_suppression_face(torch.from_numpy(pred), conf_thres=0.3, iou_thres=0.5)
94 |
95 | # ============可视化================
96 | img_vis(img,orgimg,pred)
97 |
98 |
99 |
--------------------------------------------------------------------------------
/yolov5-face/torch2trt/readme.md:
--------------------------------------------------------------------------------
1 | English | [简体中文](readme_CN.md)
2 |
3 |
4 |
5 | # Overall process
6 |
7 | ## 1.Pytorch->TensorRT
8 |
9 | ```shell
10 | python export.py --weights "torch's path" --onnx2trt --fp16_trt
11 | ```
12 |
13 |
14 | ## 2.TensorRT inference
15 | ```shell
16 | python torch2trt/main.py --trt_path "trt's path"
17 | ```
18 | Image preprocessing -> TensorRT inference -> visualization
19 |
20 |
21 |
22 | # Time-consuming comparison
23 |
24 | | Backbone |Pytorch(ms) |TensorRT_FP16(ms) |
25 | |:---:|:----:|:----:|
26 | |yolov5n-0.5| 7.7 | 2.1 |
27 | |yolov5n-face| 7.7 | 2.4 |
28 | |yolov5s-face| 5.6 | 2.2 |
29 | |yolov5m-face| 9.9 | 3.3 |
30 | |yolov5l-face| 15.9 | 4.5 |
31 |
32 | > Pytorch=1.10.0+cu102 TensorRT=8.2.0.6 Hardware=rtx2080ti
33 |
34 | ```shell
35 | python torch2trt/speed.py --torch_path "torch's path" --trt_path "trt's path"
36 | ```
37 |
38 |
39 |
40 | # Visualization
41 |
42 |
43 |
44 | yolov5n-0.5 |
45 | yolov5n-face |
46 |
47 |
48 |  |
49 |  |
50 |
51 |
52 |
53 |
54 |
55 | yolov5s-face |
56 | yolov5m-face |
57 | yolov5l-face |
58 |
59 |
60 |  |
61 |  |
62 |  |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/yolov5-face/torch2trt/readme_CN.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # 整体流程
4 |
5 | ## 1.Pytorch->TensorRT
6 |
7 | ```shell
8 | python export.py --weights "torch权重路径" --onnx2trt --fp16_trt
9 | ```
10 |
11 |
12 | ## 2.TensorRT推理
13 | ```shell
14 | python torch2trt/main.py --trt_path "trt权重路径"
15 | ```
16 |
17 | 图像预处理 -> TensorRT推理 -> 可视化结果
18 |
19 |
20 |
21 | # 耗时对比
22 |
23 | | | Pytorch(ms) | TensorRT_FP16(ms) |
24 | |:---:|:----:|:----:|
25 | | yolov5n-0.5 | 7.7 | 2.1 |
26 | | yolov5n-face | 7.7 | 2.4 |
27 | | yolov5s-face | 5.6 | 2.2 |
28 | | yolov5m-face | 9.9 | 3.3 |
29 | | yolov5l-face | 15.9 | 4.5 |
30 |
31 | > Pytorch=1.10.0+cu102 TensorRT=8.2.0.6 Hardware=rtx2080ti
32 |
33 | ```shell
34 | python torch2trt/speed.py --torch_path "torch权重路径" --trt_path "trt权重路径"
35 | ```
36 |
37 |
38 |
39 | # 可视化
40 |
41 |
42 |
43 | yolov5n-0.5 |
44 | yolov5n-face |
45 |
46 |
47 |  |
48 |  |
49 |
50 |
51 |
52 |
53 |
54 | yolov5s-face |
55 | yolov5m-face |
56 | yolov5l-face |
57 |
58 |
59 |  |
60 |  |
61 |  |
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/yolov5-face/torch2trt/sample.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IS2AI/AnyFace/bed844d23be03334f7fc12b2c4fb3ba2ac530bab/yolov5-face/torch2trt/sample.jpg
--------------------------------------------------------------------------------
/yolov5-face/torch2trt/speed.py:
--------------------------------------------------------------------------------
1 | from models.experimental import attempt_load
2 | from torch2trt.trt_model import TrtModel
3 | import argparse
4 | import torch
5 | import time
6 | from tqdm import tqdm
7 |
8 |
9 | def run(model,img,warmup_iter,iter):
10 |
11 |
12 | print('start warm up...')
13 | for _ in tqdm(range(warmup_iter)):
14 | model(img)
15 |
16 |
17 | print('start calculate...')
18 | torch.cuda.synchronize()
19 | start = time.time()
20 | for __ in tqdm(range(iter)):
21 | model(img)
22 | torch.cuda.synchronize()
23 | end = time.time()
24 | return ((end - start) * 1000)/float(iter)
25 |
26 | if __name__ == '__main__':
27 | parser = argparse.ArgumentParser()
28 | parser.add_argument('--torch_path', type=str,required=True, help='torch weights path')
29 | parser.add_argument('--trt_path', type=str,required=True, help='tensorrt weights path')
30 |
31 | parser.add_argument('--device', type=int,default=0, help='cuda device')
32 | parser.add_argument('--img_shape', type=list,default=[1,3,640,640], help='tensorrt weights path')
33 | parser.add_argument('--warmup_iter', type=int, default=100,help='warm up iter')
34 | parser.add_argument('--iter', type=int, default=300,help='average elapsed time of iterations')
35 | opt = parser.parse_args()
36 |
37 |
38 | # -----------------------torch-----------------------------------------
39 | img = torch.zeros(opt.img_shape)
40 | model = attempt_load(opt.torch_path, map_location=torch.device('cpu')) # load FP32 model
41 | model.eval()
42 | total_time=run(model.to(opt.device),img.to(opt.device),opt.warmup_iter,opt.iter)
43 | print('Pytorch is %.2f ms/img'%total_time)
44 |
45 | # -----------------------tensorrt-----------------------------------------
46 | model=TrtModel(opt.trt_path)
47 | total_time=run(model,img.numpy(),opt.warmup_iter,opt.iter)
48 | model.destroy()
49 | print('TensorRT is %.2f ms/img'%total_time)
50 |
--------------------------------------------------------------------------------
/yolov5-face/torch2trt/trt_model.py:
--------------------------------------------------------------------------------
1 | import pycuda.autoinit
2 | import pycuda.driver as cuda
3 | import tensorrt as trt
4 | import numpy as np
5 |
6 | EXPLICIT_BATCH = 1 << (int)(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH)
7 | TRT_LOGGER = trt.Logger(trt.Logger.WARNING)
8 | def GiB(val):
9 | return val * 1 << 30
10 |
11 | def ONNX_to_TRT(onnx_model_path=None,trt_engine_path=None,fp16_mode=False):
12 | """
13 | 仅适用TensorRT V8版本
14 | 生成cudaEngine,并保存引擎文件(仅支持固定输入尺度)
15 |
16 | fp16_mode: True则fp16预测
17 | onnx_model_path: 将加载的onnx权重路径
18 | trt_engine_path: trt引擎文件保存路径
19 | """
20 | builder = trt.Builder(TRT_LOGGER)
21 | network = builder.create_network(EXPLICIT_BATCH)
22 | parser = trt.OnnxParser(network, TRT_LOGGER)
23 |
24 | config = builder.create_builder_config()
25 | config.max_workspace_size=GiB(1)
26 | if fp16_mode:
27 | config.set_flag(trt.BuilderFlag.FP16)
28 | with open(onnx_model_path, 'rb') as model:
29 | assert parser.parse(model.read())
30 | serialized_engine=builder.build_serialized_network(network, config)
31 |
32 |
33 | with open(trt_engine_path, 'wb') as f:
34 | f.write(serialized_engine) # 序列化
35 |
36 | print('TensorRT file in ' + trt_engine_path)
37 | print('============ONNX->TensorRT SUCCESS============')
38 |
39 | class TrtModel():
40 | '''
41 | TensorRT infer
42 | '''
43 | def __init__(self,trt_path):
44 | self.ctx=cuda.Device(0).make_context()
45 | stream = cuda.Stream()
46 | TRT_LOGGER = trt.Logger(trt.Logger.INFO)
47 | runtime = trt.Runtime(TRT_LOGGER)
48 |
49 | # Deserialize the engine from file
50 | with open(trt_path, "rb") as f:
51 | engine = runtime.deserialize_cuda_engine(f.read())
52 | context = engine.create_execution_context()
53 |
54 | host_inputs = []
55 | cuda_inputs = []
56 | host_outputs = []
57 | cuda_outputs = []
58 | bindings = []
59 |
60 | for binding in engine:
61 | print('bingding:', binding, engine.get_binding_shape(binding))
62 | size = trt.volume(engine.get_binding_shape(binding)) * engine.max_batch_size
63 | dtype = trt.nptype(engine.get_binding_dtype(binding))
64 | # Allocate host and device buffers
65 | host_mem = cuda.pagelocked_empty(size, dtype)
66 | cuda_mem = cuda.mem_alloc(host_mem.nbytes)
67 | # Append the device buffer to device bindings.
68 | bindings.append(int(cuda_mem))
69 | # Append to the appropriate list.
70 | if engine.binding_is_input(binding):
71 | self.input_w = engine.get_binding_shape(binding)[-1]
72 | self.input_h = engine.get_binding_shape(binding)[-2]
73 | host_inputs.append(host_mem)
74 | cuda_inputs.append(cuda_mem)
75 | else:
76 | host_outputs.append(host_mem)
77 | cuda_outputs.append(cuda_mem)
78 |
79 | # Store
80 | self.stream = stream
81 | self.context = context
82 | self.engine = engine
83 | self.host_inputs = host_inputs
84 | self.cuda_inputs = cuda_inputs
85 | self.host_outputs = host_outputs
86 | self.cuda_outputs = cuda_outputs
87 | self.bindings = bindings
88 | self.batch_size = engine.max_batch_size
89 |
90 | def __call__(self,img_np_nchw):
91 | '''
92 | TensorRT推理
93 | :param img_np_nchw: 输入图像
94 | '''
95 | self.ctx.push()
96 |
97 | # Restore
98 | stream = self.stream
99 | context = self.context
100 | engine = self.engine
101 | host_inputs = self.host_inputs
102 | cuda_inputs = self.cuda_inputs
103 | host_outputs = self.host_outputs
104 | cuda_outputs = self.cuda_outputs
105 | bindings = self.bindings
106 |
107 | np.copyto(host_inputs[0], img_np_nchw.ravel())
108 | cuda.memcpy_htod_async(cuda_inputs[0], host_inputs[0], stream)
109 | context.execute_async(batch_size=self.batch_size, bindings=bindings, stream_handle=stream.handle)
110 | cuda.memcpy_dtoh_async(host_outputs[0], cuda_outputs[0], stream)
111 | stream.synchronize()
112 | self.ctx.pop()
113 | return host_outputs[0]
114 |
115 |
116 | def destroy(self):
117 | # Remove any context from the top of the context stack, deactivating it.
118 | self.ctx.pop()
119 |
--------------------------------------------------------------------------------
/yolov5-face/utils/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IS2AI/AnyFace/bed844d23be03334f7fc12b2c4fb3ba2ac530bab/yolov5-face/utils/__init__.py
--------------------------------------------------------------------------------
/yolov5-face/utils/activations.py:
--------------------------------------------------------------------------------
1 | # Activation functions
2 |
3 | import torch
4 | import torch.nn as nn
5 | import torch.nn.functional as F
6 |
7 |
8 | # SiLU https://arxiv.org/pdf/1606.08415.pdf ----------------------------------------------------------------------------
9 | class SiLU(nn.Module): # export-friendly version of nn.SiLU()
10 | @staticmethod
11 | def forward(x):
12 | return x * torch.sigmoid(x)
13 |
14 |
15 | class Hardswish(nn.Module): # export-friendly version of nn.Hardswish()
16 | @staticmethod
17 | def forward(x):
18 | # return x * F.hardsigmoid(x) # for torchscript and CoreML
19 | return x * F.hardtanh(x + 3, 0., 6.) / 6. # for torchscript, CoreML and ONNX
20 |
21 |
22 | class MemoryEfficientSwish(nn.Module):
23 | class F(torch.autograd.Function):
24 | @staticmethod
25 | def forward(ctx, x):
26 | ctx.save_for_backward(x)
27 | return x * torch.sigmoid(x)
28 |
29 | @staticmethod
30 | def backward(ctx, grad_output):
31 | x = ctx.saved_tensors[0]
32 | sx = torch.sigmoid(x)
33 | return grad_output * (sx * (1 + x * (1 - sx)))
34 |
35 | def forward(self, x):
36 | return self.F.apply(x)
37 |
38 |
39 | # Mish https://github.com/digantamisra98/Mish --------------------------------------------------------------------------
40 | class Mish(nn.Module):
41 | @staticmethod
42 | def forward(x):
43 | return x * F.softplus(x).tanh()
44 |
45 |
46 | class MemoryEfficientMish(nn.Module):
47 | class F(torch.autograd.Function):
48 | @staticmethod
49 | def forward(ctx, x):
50 | ctx.save_for_backward(x)
51 | return x.mul(torch.tanh(F.softplus(x))) # x * tanh(ln(1 + exp(x)))
52 |
53 | @staticmethod
54 | def backward(ctx, grad_output):
55 | x = ctx.saved_tensors[0]
56 | sx = torch.sigmoid(x)
57 | fx = F.softplus(x).tanh()
58 | return grad_output * (fx + x * sx * (1 - fx * fx))
59 |
60 | def forward(self, x):
61 | return self.F.apply(x)
62 |
63 |
64 | # FReLU https://arxiv.org/abs/2007.11824 -------------------------------------------------------------------------------
65 | class FReLU(nn.Module):
66 | def __init__(self, c1, k=3): # ch_in, kernel
67 | super().__init__()
68 | self.conv = nn.Conv2d(c1, c1, k, 1, 1, groups=c1, bias=False)
69 | self.bn = nn.BatchNorm2d(c1)
70 |
71 | def forward(self, x):
72 | return torch.max(x, self.bn(self.conv(x)))
73 |
--------------------------------------------------------------------------------
/yolov5-face/utils/autoanchor.py:
--------------------------------------------------------------------------------
1 | # Auto-anchor utils
2 |
3 | import numpy as np
4 | import torch
5 | import yaml
6 | from scipy.cluster.vq import kmeans
7 | from tqdm import tqdm
8 |
9 | from utils.general import colorstr
10 |
11 |
12 | def check_anchor_order(m):
13 | # Check anchor order against stride order for YOLOv5 Detect() module m, and correct if necessary
14 | a = m.anchor_grid.prod(-1).view(-1) # anchor area
15 | da = a[-1] - a[0] # delta a
16 | ds = m.stride[-1] - m.stride[0] # delta s
17 | if da.sign() != ds.sign(): # same order
18 | print('Reversing anchor order')
19 | m.anchors[:] = m.anchors.flip(0)
20 | m.anchor_grid[:] = m.anchor_grid.flip(0)
21 |
22 |
23 | def check_anchors(dataset, model, thr=4.0, imgsz=640):
24 | # Check anchor fit to data, recompute if necessary
25 | prefix = colorstr('autoanchor: ')
26 | print(f'\n{prefix}Analyzing anchors... ', end='')
27 | m = model.module.model[-1] if hasattr(model, 'module') else model.model[-1] # Detect()
28 | shapes = imgsz * dataset.shapes / dataset.shapes.max(1, keepdims=True)
29 | scale = np.random.uniform(0.9, 1.1, size=(shapes.shape[0], 1)) # augment scale
30 | wh = torch.tensor(np.concatenate([l[:, 3:5] * s for s, l in zip(shapes * scale, dataset.labels)])).float() # wh
31 |
32 | def metric(k): # compute metric
33 | r = wh[:, None] / k[None]
34 | x = torch.min(r, 1. / r).min(2)[0] # ratio metric
35 | best = x.max(1)[0] # best_x
36 | aat = (x > 1. / thr).float().sum(1).mean() # anchors above threshold
37 | bpr = (best > 1. / thr).float().mean() # best possible recall
38 | return bpr, aat
39 |
40 | bpr, aat = metric(m.anchor_grid.clone().cpu().view(-1, 2))
41 | print(f'anchors/target = {aat:.2f}, Best Possible Recall (BPR) = {bpr:.4f}', end='')
42 | if bpr < 0.98: # threshold to recompute
43 | print('. Attempting to improve anchors, please wait...')
44 | na = m.anchor_grid.numel() // 2 # number of anchors
45 | new_anchors = kmean_anchors(dataset, n=na, img_size=imgsz, thr=thr, gen=1000, verbose=False)
46 | new_bpr = metric(new_anchors.reshape(-1, 2))[0]
47 | if new_bpr > bpr: # replace anchors
48 | new_anchors = torch.tensor(new_anchors, device=m.anchors.device).type_as(m.anchors)
49 | m.anchor_grid[:] = new_anchors.clone().view_as(m.anchor_grid) # for inference
50 | m.anchors[:] = new_anchors.clone().view_as(m.anchors) / m.stride.to(m.anchors.device).view(-1, 1, 1) # loss
51 | check_anchor_order(m)
52 | print(f'{prefix}New anchors saved to model. Update model *.yaml to use these anchors in the future.')
53 | else:
54 | print(f'{prefix}Original anchors better than new anchors. Proceeding with original anchors.')
55 | print('') # newline
56 |
57 |
58 | def kmean_anchors(path='./data/coco128.yaml', n=9, img_size=640, thr=4.0, gen=1000, verbose=True):
59 | """ Creates kmeans-evolved anchors from training dataset
60 |
61 | Arguments:
62 | path: path to dataset *.yaml, or a loaded dataset
63 | n: number of anchors
64 | img_size: image size used for training
65 | thr: anchor-label wh ratio threshold hyperparameter hyp['anchor_t'] used for training, default=4.0
66 | gen: generations to evolve anchors using genetic algorithm
67 | verbose: print all results
68 |
69 | Return:
70 | k: kmeans evolved anchors
71 |
72 | Usage:
73 | from utils.autoanchor import *; _ = kmean_anchors()
74 | """
75 | thr = 1. / thr
76 | prefix = colorstr('autoanchor: ')
77 |
78 | def metric(k, wh): # compute metrics
79 | r = wh[:, None] / k[None]
80 | x = torch.min(r, 1. / r).min(2)[0] # ratio metric
81 | # x = wh_iou(wh, torch.tensor(k)) # iou metric
82 | return x, x.max(1)[0] # x, best_x
83 |
84 | def anchor_fitness(k): # mutation fitness
85 | _, best = metric(torch.tensor(k, dtype=torch.float32), wh)
86 | return (best * (best > thr).float()).mean() # fitness
87 |
88 | def print_results(k):
89 | k = k[np.argsort(k.prod(1))] # sort small to large
90 | x, best = metric(k, wh0)
91 | bpr, aat = (best > thr).float().mean(), (x > thr).float().mean() * n # best possible recall, anch > thr
92 | print(f'{prefix}thr={thr:.2f}: {bpr:.4f} best possible recall, {aat:.2f} anchors past thr')
93 | print(f'{prefix}n={n}, img_size={img_size}, metric_all={x.mean():.3f}/{best.mean():.3f}-mean/best, '
94 | f'past_thr={x[x > thr].mean():.3f}-mean: ', end='')
95 | for i, x in enumerate(k):
96 | print('%i,%i' % (round(x[0]), round(x[1])), end=', ' if i < len(k) - 1 else '\n') # use in *.cfg
97 | return k
98 |
99 | if isinstance(path, str): # *.yaml file
100 | with open(path) as f:
101 | data_dict = yaml.load(f, Loader=yaml.SafeLoader) # model dict
102 | from utils.datasets import LoadImagesAndLabels
103 | dataset = LoadImagesAndLabels(data_dict['train'], augment=True, rect=True)
104 | else:
105 | dataset = path # dataset
106 |
107 | # Get label wh
108 | shapes = img_size * dataset.shapes / dataset.shapes.max(1, keepdims=True)
109 | wh0 = np.concatenate([l[:, 3:5] * s for s, l in zip(shapes, dataset.labels)]) # wh
110 |
111 | # Filter
112 | i = (wh0 < 3.0).any(1).sum()
113 | if i:
114 | print(f'{prefix}WARNING: Extremely small objects found. {i} of {len(wh0)} labels are < 3 pixels in size.')
115 | wh = wh0[(wh0 >= 2.0).any(1)] # filter > 2 pixels
116 | # wh = wh * (np.random.rand(wh.shape[0], 1) * 0.9 + 0.1) # multiply by random scale 0-1
117 |
118 | # Kmeans calculation
119 | print(f'{prefix}Running kmeans for {n} anchors on {len(wh)} points...')
120 | s = wh.std(0) # sigmas for whitening
121 | k, dist = kmeans(wh / s, n, iter=30) # points, mean distance
122 | k *= s
123 | wh = torch.tensor(wh, dtype=torch.float32) # filtered
124 | wh0 = torch.tensor(wh0, dtype=torch.float32) # unfiltered
125 | k = print_results(k)
126 |
127 | # Plot
128 | # k, d = [None] * 20, [None] * 20
129 | # for i in tqdm(range(1, 21)):
130 | # k[i-1], d[i-1] = kmeans(wh / s, i) # points, mean distance
131 | # fig, ax = plt.subplots(1, 2, figsize=(14, 7), tight_layout=True)
132 | # ax = ax.ravel()
133 | # ax[0].plot(np.arange(1, 21), np.array(d) ** 2, marker='.')
134 | # fig, ax = plt.subplots(1, 2, figsize=(14, 7)) # plot wh
135 | # ax[0].hist(wh[wh[:, 0]<100, 0],400)
136 | # ax[1].hist(wh[wh[:, 1]<100, 1],400)
137 | # fig.savefig('wh.png', dpi=200)
138 |
139 | # Evolve
140 | npr = np.random
141 | f, sh, mp, s = anchor_fitness(k), k.shape, 0.9, 0.1 # fitness, generations, mutation prob, sigma
142 | pbar = tqdm(range(gen), desc=f'{prefix}Evolving anchors with Genetic Algorithm:') # progress bar
143 | for _ in pbar:
144 | v = np.ones(sh)
145 | while (v == 1).all(): # mutate until a change occurs (prevent duplicates)
146 | v = ((npr.random(sh) < mp) * npr.random() * npr.randn(*sh) * s + 1).clip(0.3, 3.0)
147 | kg = (k.copy() * v).clip(min=2.0)
148 | fg = anchor_fitness(kg)
149 | if fg > f:
150 | f, k = fg, kg.copy()
151 | pbar.desc = f'{prefix}Evolving anchors with Genetic Algorithm: fitness = {f:.4f}'
152 | if verbose:
153 | print_results(k)
154 |
155 | return print_results(k)
156 |
--------------------------------------------------------------------------------
/yolov5-face/utils/aws/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IS2AI/AnyFace/bed844d23be03334f7fc12b2c4fb3ba2ac530bab/yolov5-face/utils/aws/__init__.py
--------------------------------------------------------------------------------
/yolov5-face/utils/aws/mime.sh:
--------------------------------------------------------------------------------
1 | # AWS EC2 instance startup 'MIME' script https://aws.amazon.com/premiumsupport/knowledge-center/execute-user-data-ec2/
2 | # This script will run on every instance restart, not only on first start
3 | # --- DO NOT COPY ABOVE COMMENTS WHEN PASTING INTO USERDATA ---
4 |
5 | Content-Type: multipart/mixed; boundary="//"
6 | MIME-Version: 1.0
7 |
8 | --//
9 | Content-Type: text/cloud-config; charset="us-ascii"
10 | MIME-Version: 1.0
11 | Content-Transfer-Encoding: 7bit
12 | Content-Disposition: attachment; filename="cloud-config.txt"
13 |
14 | #cloud-config
15 | cloud_final_modules:
16 | - [scripts-user, always]
17 |
18 | --//
19 | Content-Type: text/x-shellscript; charset="us-ascii"
20 | MIME-Version: 1.0
21 | Content-Transfer-Encoding: 7bit
22 | Content-Disposition: attachment; filename="userdata.txt"
23 |
24 | #!/bin/bash
25 | # --- paste contents of userdata.sh here ---
26 | --//
27 |
--------------------------------------------------------------------------------
/yolov5-face/utils/aws/resume.py:
--------------------------------------------------------------------------------
1 | # Resume all interrupted trainings in yolov5/ dir including DDP trainings
2 | # Usage: $ python utils/aws/resume.py
3 |
4 | import os
5 | import sys
6 | from pathlib import Path
7 |
8 | import torch
9 | import yaml
10 |
11 | sys.path.append('./') # to run '$ python *.py' files in subdirectories
12 |
13 | port = 0 # --master_port
14 | path = Path('').resolve()
15 | for last in path.rglob('*/**/last.pt'):
16 | ckpt = torch.load(last)
17 | if ckpt['optimizer'] is None:
18 | continue
19 |
20 | # Load opt.yaml
21 | with open(last.parent.parent / 'opt.yaml') as f:
22 | opt = yaml.load(f, Loader=yaml.SafeLoader)
23 |
24 | # Get device count
25 | d = opt['device'].split(',') # devices
26 | nd = len(d) # number of devices
27 | ddp = nd > 1 or (nd == 0 and torch.cuda.device_count() > 1) # distributed data parallel
28 |
29 | if ddp: # multi-GPU
30 | port += 1
31 | cmd = f'python -m torch.distributed.launch --nproc_per_node {nd} --master_port {port} train.py --resume {last}'
32 | else: # single-GPU
33 | cmd = f'python train.py --resume {last}'
34 |
35 | cmd += ' > /dev/null 2>&1 &' # redirect output to dev/null and run in daemon thread
36 | print(cmd)
37 | os.system(cmd)
38 |
--------------------------------------------------------------------------------
/yolov5-face/utils/aws/userdata.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # AWS EC2 instance startup script https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html
3 | # This script will run only once on first instance start (for a re-start script see mime.sh)
4 | # /home/ubuntu (ubuntu) or /home/ec2-user (amazon-linux) is working dir
5 | # Use >300 GB SSD
6 |
7 | cd home/ubuntu
8 | if [ ! -d yolov5 ]; then
9 | echo "Running first-time script." # install dependencies, download COCO, pull Docker
10 | git clone https://github.com/ultralytics/yolov5 && sudo chmod -R 777 yolov5
11 | cd yolov5
12 | bash data/scripts/get_coco.sh && echo "Data done." &
13 | sudo docker pull ultralytics/yolov5:latest && echo "Docker done." &
14 | python -m pip install --upgrade pip && pip install -r requirements.txt && python detect.py && echo "Requirements done." &
15 | wait && echo "All tasks done." # finish background tasks
16 | else
17 | echo "Running re-start script." # resume interrupted runs
18 | i=0
19 | list=$(sudo docker ps -qa) # container list i.e. $'one\ntwo\nthree\nfour'
20 | while IFS= read -r id; do
21 | ((i++))
22 | echo "restarting container $i: $id"
23 | sudo docker start $id
24 | # sudo docker exec -it $id python train.py --resume # single-GPU
25 | sudo docker exec -d $id python utils/aws/resume.py # multi-scenario
26 | done <<<"$list"
27 | fi
28 |
--------------------------------------------------------------------------------
/yolov5-face/utils/google_app_engine/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM gcr.io/google-appengine/python
2 |
3 | # Create a virtualenv for dependencies. This isolates these packages from
4 | # system-level packages.
5 | # Use -p python3 or -p python3.7 to select python version. Default is version 2.
6 | RUN virtualenv /env -p python3
7 |
8 | # Setting these environment variables are the same as running
9 | # source /env/bin/activate.
10 | ENV VIRTUAL_ENV /env
11 | ENV PATH /env/bin:$PATH
12 |
13 | RUN apt-get update && apt-get install -y python-opencv
14 |
15 | # Copy the application's requirements.txt and run pip to install all
16 | # dependencies into the virtualenv.
17 | ADD requirements.txt /app/requirements.txt
18 | RUN pip install -r /app/requirements.txt
19 |
20 | # Add the application source code.
21 | ADD . /app
22 |
23 | # Run a WSGI server to serve the application. gunicorn must be declared as
24 | # a dependency in requirements.txt.
25 | CMD gunicorn -b :$PORT main:app
26 |
--------------------------------------------------------------------------------
/yolov5-face/utils/google_app_engine/additional_requirements.txt:
--------------------------------------------------------------------------------
1 | # add these requirements in your app on top of the existing ones
2 | pip==18.1
3 | Flask==1.0.2
4 | gunicorn==19.9.0
5 |
--------------------------------------------------------------------------------
/yolov5-face/utils/google_app_engine/app.yaml:
--------------------------------------------------------------------------------
1 | runtime: custom
2 | env: flex
3 |
4 | service: yolov5app
5 |
6 | liveness_check:
7 | initial_delay_sec: 600
8 |
9 | manual_scaling:
10 | instances: 1
11 | resources:
12 | cpu: 1
13 | memory_gb: 4
14 | disk_size_gb: 20
--------------------------------------------------------------------------------
/yolov5-face/utils/google_utils.py:
--------------------------------------------------------------------------------
1 | # Google utils: https://cloud.google.com/storage/docs/reference/libraries
2 |
3 | import os
4 | import platform
5 | import subprocess
6 | import time
7 | from pathlib import Path
8 |
9 | import requests
10 | import torch
11 |
12 |
13 | def gsutil_getsize(url=''):
14 | # gs://bucket/file size https://cloud.google.com/storage/docs/gsutil/commands/du
15 | s = subprocess.check_output(f'gsutil du {url}', shell=True).decode('utf-8')
16 | return eval(s.split(' ')[0]) if len(s) else 0 # bytes
17 |
18 |
19 | def attempt_download(file, repo='ultralytics/yolov5'):
20 | # Attempt file download if does not exist
21 | file = Path(str(file).strip().replace("'", '').lower())
22 |
23 | if not file.exists():
24 | try:
25 | response = requests.get(f'https://api.github.com/repos/{repo}/releases/latest').json() # github api
26 | assets = [x['name'] for x in response['assets']] # release assets, i.e. ['yolov5s.pt', 'yolov5m.pt', ...]
27 | tag = response['tag_name'] # i.e. 'v1.0'
28 | except: # fallback plan
29 | assets = ['yolov5.pt', 'yolov5.pt', 'yolov5l.pt', 'yolov5x.pt']
30 | tag = subprocess.check_output('git tag', shell=True).decode('utf-8').split('\n')[-2]
31 |
32 | name = file.name
33 | if name in assets:
34 | msg = f'{file} missing, try downloading from https://github.com/{repo}/releases/'
35 | redundant = False # second download option
36 | try: # GitHub
37 | url = f'https://github.com/{repo}/releases/download/{tag}/{name}'
38 | print(f'Downloading {url} to {file}...')
39 | torch.hub.download_url_to_file(url, file)
40 | assert file.exists() and file.stat().st_size > 1E6 # check
41 | except Exception as e: # GCP
42 | print(f'Download error: {e}')
43 | assert redundant, 'No secondary mirror'
44 | url = f'https://storage.googleapis.com/{repo}/ckpt/{name}'
45 | print(f'Downloading {url} to {file}...')
46 | os.system(f'curl -L {url} -o {file}') # torch.hub.download_url_to_file(url, weights)
47 | finally:
48 | if not file.exists() or file.stat().st_size < 1E6: # check
49 | file.unlink(missing_ok=True) # remove partial downloads
50 | print(f'ERROR: Download failure: {msg}')
51 | print('')
52 | return
53 |
54 |
55 | def gdrive_download(id='16TiPfZj7htmTyhntwcZyEEAejOUxuT6m', file='tmp.zip'):
56 | # Downloads a file from Google Drive. from yolov5.utils.google_utils import *; gdrive_download()
57 | t = time.time()
58 | file = Path(file)
59 | cookie = Path('cookie') # gdrive cookie
60 | print(f'Downloading https://drive.google.com/uc?export=download&id={id} as {file}... ', end='')
61 | file.unlink(missing_ok=True) # remove existing file
62 | cookie.unlink(missing_ok=True) # remove existing cookie
63 |
64 | # Attempt file download
65 | out = "NUL" if platform.system() == "Windows" else "/dev/null"
66 | os.system(f'curl -c ./cookie -s -L "drive.google.com/uc?export=download&id={id}" > {out}')
67 | if os.path.exists('cookie'): # large file
68 | s = f'curl -Lb ./cookie "drive.google.com/uc?export=download&confirm={get_token()}&id={id}" -o {file}'
69 | else: # small file
70 | s = f'curl -s -L -o {file} "drive.google.com/uc?export=download&id={id}"'
71 | r = os.system(s) # execute, capture return
72 | cookie.unlink(missing_ok=True) # remove existing cookie
73 |
74 | # Error check
75 | if r != 0:
76 | file.unlink(missing_ok=True) # remove partial
77 | print('Download error ') # raise Exception('Download error')
78 | return r
79 |
80 | # Unzip if archive
81 | if file.suffix == '.zip':
82 | print('unzipping... ', end='')
83 | os.system(f'unzip -q {file}') # unzip
84 | file.unlink() # remove zip to free space
85 |
86 | print(f'Done ({time.time() - t:.1f}s)')
87 | return r
88 |
89 |
90 | def get_token(cookie="./cookie"):
91 | with open(cookie) as f:
92 | for line in f:
93 | if "download" in line:
94 | return line.split()[-1]
95 | return ""
96 |
97 | # def upload_blob(bucket_name, source_file_name, destination_blob_name):
98 | # # Uploads a file to a bucket
99 | # # https://cloud.google.com/storage/docs/uploading-objects#storage-upload-object-python
100 | #
101 | # storage_client = storage.Client()
102 | # bucket = storage_client.get_bucket(bucket_name)
103 | # blob = bucket.blob(destination_blob_name)
104 | #
105 | # blob.upload_from_filename(source_file_name)
106 | #
107 | # print('File {} uploaded to {}.'.format(
108 | # source_file_name,
109 | # destination_blob_name))
110 | #
111 | #
112 | # def download_blob(bucket_name, source_blob_name, destination_file_name):
113 | # # Uploads a blob from a bucket
114 | # storage_client = storage.Client()
115 | # bucket = storage_client.get_bucket(bucket_name)
116 | # blob = bucket.blob(source_blob_name)
117 | #
118 | # blob.download_to_filename(destination_file_name)
119 | #
120 | # print('Blob {} downloaded to {}.'.format(
121 | # source_blob_name,
122 | # destination_file_name))
123 |
--------------------------------------------------------------------------------
/yolov5-face/utils/infer_utils.py:
--------------------------------------------------------------------------------
1 | import torch
2 |
3 |
4 |
5 | def decode_infer(output, stride):
6 | # logging.info(torch.tensor(output.shape[0]))
7 | # logging.info(output.shape)
8 | # # bz is batch-size
9 | # bz = tuple(torch.tensor(output.shape[0]))
10 | # gridsize = tuple(torch.tensor(output.shape[-1]))
11 | # logging.info(gridsize)
12 | sh = torch.tensor(output.shape)
13 | bz = sh[0]
14 | gridsize = sh[-1]
15 |
16 | output = output.permute(0, 2, 3, 1)
17 | output = output.view(bz, gridsize, gridsize, self.gt_per_grid, 5+self.numclass)
18 | x1y1, x2y2, conf, prob = torch.split(
19 | output, [2, 2, 1, self.numclass], dim=4)
20 |
21 | shiftx = torch.arange(0, gridsize, dtype=torch.float32)
22 | shifty = torch.arange(0, gridsize, dtype=torch.float32)
23 | shifty, shiftx = torch.meshgrid([shiftx, shifty])
24 | shiftx = shiftx.unsqueeze(-1).repeat(bz, 1, 1, self.gt_per_grid)
25 | shifty = shifty.unsqueeze(-1).repeat(bz, 1, 1, self.gt_per_grid)
26 |
27 | xy_grid = torch.stack([shiftx, shifty], dim=4).cuda()
28 | x1y1 = (xy_grid+0.5-torch.exp(x1y1))*stride
29 | x2y2 = (xy_grid+0.5+torch.exp(x2y2))*stride
30 |
31 | xyxy = torch.cat((x1y1, x2y2), dim=4)
32 | conf = torch.sigmoid(conf)
33 | prob = torch.sigmoid(prob)
34 | output = torch.cat((xyxy, conf, prob), 4)
35 | output = output.view(bz, -1, 5+self.numclass)
36 | return output
--------------------------------------------------------------------------------
/yolov5-face/utils/metrics.py:
--------------------------------------------------------------------------------
1 | # Model validation metrics
2 |
3 | from pathlib import Path
4 |
5 | import matplotlib.pyplot as plt
6 | import numpy as np
7 | import torch
8 |
9 | from . import general
10 |
11 |
12 | def fitness(x):
13 | # Model fitness as a weighted combination of metrics
14 | w = [0.0, 0.0, 0.1, 0.9] # weights for [P, R, mAP@0.5, mAP@0.5:0.95]
15 | return (x[:, :4] * w).sum(1)
16 |
17 |
18 | def ap_per_class(tp, conf, pred_cls, target_cls, plot=False, save_dir='precision-recall_curve.png', names=[]):
19 | """ Compute the average precision, given the recall and precision curves.
20 | Source: https://github.com/rafaelpadilla/Object-Detection-Metrics.
21 | # Arguments
22 | tp: True positives (nparray, nx1 or nx10).
23 | conf: Objectness value from 0-1 (nparray).
24 | pred_cls: Predicted object classes (nparray).
25 | target_cls: True object classes (nparray).
26 | plot: Plot precision-recall curve at mAP@0.5
27 | save_dir: Plot save directory
28 | # Returns
29 | The average precision as computed in py-faster-rcnn.
30 | """
31 |
32 | # Sort by objectness
33 | i = np.argsort(-conf)
34 | tp, conf, pred_cls = tp[i], conf[i], pred_cls[i]
35 |
36 | # Find unique classes
37 | unique_classes = np.unique(target_cls)
38 |
39 | # Create Precision-Recall curve and compute AP for each class
40 | px, py = np.linspace(0, 1, 1000), [] # for plotting
41 | pr_score = 0.1 # score to evaluate P and R https://github.com/ultralytics/yolov3/issues/898
42 | s = [unique_classes.shape[0], tp.shape[1]] # number class, number iou thresholds (i.e. 10 for mAP0.5...0.95)
43 | ap, p, r = np.zeros(s), np.zeros(s), np.zeros(s)
44 | for ci, c in enumerate(unique_classes):
45 | i = pred_cls == c
46 | n_l = (target_cls == c).sum() # number of labels
47 | n_p = i.sum() # number of predictions
48 |
49 | if n_p == 0 or n_l == 0:
50 | continue
51 | else:
52 | # Accumulate FPs and TPs
53 | fpc = (1 - tp[i]).cumsum(0)
54 | tpc = tp[i].cumsum(0)
55 |
56 | # Recall
57 | recall = tpc / (n_l + 1e-16) # recall curve
58 | r[ci] = np.interp(-pr_score, -conf[i], recall[:, 0]) # r at pr_score, negative x, xp because xp decreases
59 |
60 | # Precision
61 | precision = tpc / (tpc + fpc) # precision curve
62 | p[ci] = np.interp(-pr_score, -conf[i], precision[:, 0]) # p at pr_score
63 |
64 | # AP from recall-precision curve
65 | for j in range(tp.shape[1]):
66 | ap[ci, j], mpre, mrec = compute_ap(recall[:, j], precision[:, j])
67 | if plot and (j == 0):
68 | py.append(np.interp(px, mrec, mpre)) # precision at mAP@0.5
69 |
70 | # Compute F1 score (harmonic mean of precision and recall)
71 | f1 = 2 * p * r / (p + r + 1e-16)
72 |
73 | if plot:
74 | plot_pr_curve(px, py, ap, save_dir, names)
75 |
76 | return p, r, ap, f1, unique_classes.astype('int32')
77 |
78 |
79 | def compute_ap(recall, precision):
80 | """ Compute the average precision, given the recall and precision curves
81 | # Arguments
82 | recall: The recall curve (list)
83 | precision: The precision curve (list)
84 | # Returns
85 | Average precision, precision curve, recall curve
86 | """
87 |
88 | # Append sentinel values to beginning and end
89 | mrec = np.concatenate(([0.], recall, [recall[-1] + 0.01]))
90 | mpre = np.concatenate(([1.], precision, [0.]))
91 |
92 | # Compute the precision envelope
93 | mpre = np.flip(np.maximum.accumulate(np.flip(mpre)))
94 |
95 | # Integrate area under curve
96 | method = 'interp' # methods: 'continuous', 'interp'
97 | if method == 'interp':
98 | x = np.linspace(0, 1, 101) # 101-point interp (COCO)
99 | ap = np.trapz(np.interp(x, mrec, mpre), x) # integrate
100 | else: # 'continuous'
101 | i = np.where(mrec[1:] != mrec[:-1])[0] # points where x axis (recall) changes
102 | ap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1]) # area under curve
103 |
104 | return ap, mpre, mrec
105 |
106 |
107 | class ConfusionMatrix:
108 | # Updated version of https://github.com/kaanakan/object_detection_confusion_matrix
109 | def __init__(self, nc, conf=0.25, iou_thres=0.45):
110 | self.matrix = np.zeros((nc + 1, nc + 1))
111 | self.nc = nc # number of classes
112 | self.conf = conf
113 | self.iou_thres = iou_thres
114 |
115 | def process_batch(self, detections, labels):
116 | """
117 | Return intersection-over-union (Jaccard index) of boxes.
118 | Both sets of boxes are expected to be in (x1, y1, x2, y2) format.
119 | Arguments:
120 | detections (Array[N, 6]), x1, y1, x2, y2, conf, class
121 | labels (Array[M, 5]), class, x1, y1, x2, y2
122 | Returns:
123 | None, updates confusion matrix accordingly
124 | """
125 | detections = detections[detections[:, 4] > self.conf]
126 | gt_classes = labels[:, 0].int()
127 | detection_classes = detections[:, 5].int()
128 | iou = general.box_iou(labels[:, 1:], detections[:, :4])
129 |
130 | x = torch.where(iou > self.iou_thres)
131 | if x[0].shape[0]:
132 | matches = torch.cat((torch.stack(x, 1), iou[x[0], x[1]][:, None]), 1).cpu().numpy()
133 | if x[0].shape[0] > 1:
134 | matches = matches[matches[:, 2].argsort()[::-1]]
135 | matches = matches[np.unique(matches[:, 1], return_index=True)[1]]
136 | matches = matches[matches[:, 2].argsort()[::-1]]
137 | matches = matches[np.unique(matches[:, 0], return_index=True)[1]]
138 | else:
139 | matches = np.zeros((0, 3))
140 |
141 | n = matches.shape[0] > 0
142 | m0, m1, _ = matches.transpose().astype(np.int16)
143 | for i, gc in enumerate(gt_classes):
144 | j = m0 == i
145 | if n and sum(j) == 1:
146 | self.matrix[gc, detection_classes[m1[j]]] += 1 # correct
147 | else:
148 | self.matrix[gc, self.nc] += 1 # background FP
149 |
150 | if n:
151 | for i, dc in enumerate(detection_classes):
152 | if not any(m1 == i):
153 | self.matrix[self.nc, dc] += 1 # background FN
154 |
155 | def matrix(self):
156 | return self.matrix
157 |
158 | def plot(self, save_dir='', names=()):
159 | try:
160 | import seaborn as sn
161 |
162 | array = self.matrix / (self.matrix.sum(0).reshape(1, self.nc + 1) + 1E-6) # normalize
163 | array[array < 0.005] = np.nan # don't annotate (would appear as 0.00)
164 |
165 | fig = plt.figure(figsize=(12, 9), tight_layout=True)
166 | sn.set(font_scale=1.0 if self.nc < 50 else 0.8) # for label size
167 | labels = (0 < len(names) < 99) and len(names) == self.nc # apply names to ticklabels
168 | sn.heatmap(array, annot=self.nc < 30, annot_kws={"size": 8}, cmap='Blues', fmt='.2f', square=True,
169 | xticklabels=names + ['background FN'] if labels else "auto",
170 | yticklabels=names + ['background FP'] if labels else "auto").set_facecolor((1, 1, 1))
171 | fig.axes[0].set_xlabel('True')
172 | fig.axes[0].set_ylabel('Predicted')
173 | fig.savefig(Path(save_dir) / 'confusion_matrix.png', dpi=250)
174 | except Exception as e:
175 | pass
176 |
177 | def print(self):
178 | for i in range(self.nc + 1):
179 | print(' '.join(map(str, self.matrix[i])))
180 |
181 |
182 | # Plots ----------------------------------------------------------------------------------------------------------------
183 |
184 | def plot_pr_curve(px, py, ap, save_dir='.', names=()):
185 | fig, ax = plt.subplots(1, 1, figsize=(9, 6), tight_layout=True)
186 | py = np.stack(py, axis=1)
187 |
188 | if 0 < len(names) < 21: # show mAP in legend if < 10 classes
189 | for i, y in enumerate(py.T):
190 | ax.plot(px, y, linewidth=1, label=f'{names[i]} %.3f' % ap[i, 0]) # plot(recall, precision)
191 | else:
192 | ax.plot(px, py, linewidth=1, color='grey') # plot(recall, precision)
193 |
194 | ax.plot(px, py.mean(1), linewidth=3, color='blue', label='all classes %.3f mAP@0.5' % ap[:, 0].mean())
195 | ax.set_xlabel('Recall')
196 | ax.set_ylabel('Precision')
197 | ax.set_xlim(0, 1)
198 | ax.set_ylim(0, 1)
199 | plt.legend(bbox_to_anchor=(1.04, 1), loc="upper left")
200 | fig.savefig(Path(save_dir) / 'precision_recall_curve.png', dpi=250)
201 |
--------------------------------------------------------------------------------
/yolov5-face/utils/wandb_logging/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IS2AI/AnyFace/bed844d23be03334f7fc12b2c4fb3ba2ac530bab/yolov5-face/utils/wandb_logging/__init__.py
--------------------------------------------------------------------------------
/yolov5-face/utils/wandb_logging/__pycache__/__init__.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IS2AI/AnyFace/bed844d23be03334f7fc12b2c4fb3ba2ac530bab/yolov5-face/utils/wandb_logging/__pycache__/__init__.cpython-38.pyc
--------------------------------------------------------------------------------
/yolov5-face/utils/wandb_logging/__pycache__/wandb_utils.cpython-38.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IS2AI/AnyFace/bed844d23be03334f7fc12b2c4fb3ba2ac530bab/yolov5-face/utils/wandb_logging/__pycache__/wandb_utils.cpython-38.pyc
--------------------------------------------------------------------------------
/yolov5-face/utils/wandb_logging/log_dataset.py:
--------------------------------------------------------------------------------
1 | import argparse
2 |
3 | import yaml
4 |
5 | from wandb_utils import WandbLogger
6 |
7 | WANDB_ARTIFACT_PREFIX = 'wandb-artifact://'
8 |
9 |
10 | def create_dataset_artifact(opt):
11 | with open(opt.data) as f:
12 | data = yaml.load(f, Loader=yaml.SafeLoader) # data dict
13 | logger = WandbLogger(opt, '', None, data, job_type='Dataset Creation')
14 |
15 |
16 | if __name__ == '__main__':
17 | parser = argparse.ArgumentParser()
18 | parser.add_argument('--data', type=str, default='data/coco128.yaml', help='data.yaml path')
19 | parser.add_argument('--single-cls', action='store_true', help='train as single-class dataset')
20 | parser.add_argument('--project', type=str, default='YOLOv5', help='name of W&B Project')
21 | opt = parser.parse_args()
22 | opt.resume = False # Explicitly disallow resume check for dataset upload job
23 |
24 | create_dataset_artifact(opt)
25 |
--------------------------------------------------------------------------------
/yolov5-face/weights/download_weights.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Download latest models from https://github.com/ultralytics/yolov5/releases
3 | # Usage:
4 | # $ bash weights/download_weights.sh
5 |
6 | python3 - < -g
20 | ````
21 |
22 | ## Bugs & Problems
23 | please issue
24 |
25 | ## Acknowledgements
26 |
27 | some code borrowed from Sergey Karayev
28 |
--------------------------------------------------------------------------------
/yolov5-face/widerface_evaluate/bbox.cpython-37m-x86_64-linux-gnu.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IS2AI/AnyFace/bed844d23be03334f7fc12b2c4fb3ba2ac530bab/yolov5-face/widerface_evaluate/bbox.cpython-37m-x86_64-linux-gnu.so
--------------------------------------------------------------------------------
/yolov5-face/widerface_evaluate/bbox.cpython-38-x86_64-linux-gnu.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IS2AI/AnyFace/bed844d23be03334f7fc12b2c4fb3ba2ac530bab/yolov5-face/widerface_evaluate/bbox.cpython-38-x86_64-linux-gnu.so
--------------------------------------------------------------------------------
/yolov5-face/widerface_evaluate/box_overlaps.pyx:
--------------------------------------------------------------------------------
1 | # --------------------------------------------------------
2 | # Fast R-CNN
3 | # Copyright (c) 2015 Microsoft
4 | # Licensed under The MIT License [see LICENSE for details]
5 | # Written by Sergey Karayev
6 | # --------------------------------------------------------
7 |
8 | cimport cython
9 | import numpy as np
10 | cimport numpy as np
11 |
12 | DTYPE = np.float
13 | ctypedef np.float_t DTYPE_t
14 |
15 | def bbox_overlaps(
16 | np.ndarray[DTYPE_t, ndim=2] boxes,
17 | np.ndarray[DTYPE_t, ndim=2] query_boxes):
18 | """
19 | Parameters
20 | ----------
21 | boxes: (N, 4) ndarray of float
22 | query_boxes: (K, 4) ndarray of float
23 | Returns
24 | -------
25 | overlaps: (N, K) ndarray of overlap between boxes and query_boxes
26 | """
27 | cdef unsigned int N = boxes.shape[0]
28 | cdef unsigned int K = query_boxes.shape[0]
29 | cdef np.ndarray[DTYPE_t, ndim=2] overlaps = np.zeros((N, K), dtype=DTYPE)
30 | cdef DTYPE_t iw, ih, box_area
31 | cdef DTYPE_t ua
32 | cdef unsigned int k, n
33 | for k in range(K):
34 | box_area = (
35 | (query_boxes[k, 2] - query_boxes[k, 0] + 1) *
36 | (query_boxes[k, 3] - query_boxes[k, 1] + 1)
37 | )
38 | for n in range(N):
39 | iw = (
40 | min(boxes[n, 2], query_boxes[k, 2]) -
41 | max(boxes[n, 0], query_boxes[k, 0]) + 1
42 | )
43 | if iw > 0:
44 | ih = (
45 | min(boxes[n, 3], query_boxes[k, 3]) -
46 | max(boxes[n, 1], query_boxes[k, 1]) + 1
47 | )
48 | if ih > 0:
49 | ua = float(
50 | (boxes[n, 2] - boxes[n, 0] + 1) *
51 | (boxes[n, 3] - boxes[n, 1] + 1) +
52 | box_area - iw * ih
53 | )
54 | overlaps[n, k] = iw * ih / ua
55 | return overlaps
--------------------------------------------------------------------------------
/yolov5-face/widerface_evaluate/build/temp.linux-x86_64-3.7/box_overlaps.o:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IS2AI/AnyFace/bed844d23be03334f7fc12b2c4fb3ba2ac530bab/yolov5-face/widerface_evaluate/build/temp.linux-x86_64-3.7/box_overlaps.o
--------------------------------------------------------------------------------
/yolov5-face/widerface_evaluate/build/temp.linux-x86_64-3.8/box_overlaps.o:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IS2AI/AnyFace/bed844d23be03334f7fc12b2c4fb3ba2ac530bab/yolov5-face/widerface_evaluate/build/temp.linux-x86_64-3.8/box_overlaps.o
--------------------------------------------------------------------------------
/yolov5-face/widerface_evaluate/evaluation.py:
--------------------------------------------------------------------------------
1 | """
2 | WiderFace evaluation code
3 | author: wondervictor
4 | mail: tianhengcheng@gmail.com
5 | copyright@wondervictor
6 | """
7 |
8 | import os
9 | import tqdm
10 | import pickle
11 | import argparse
12 | import numpy as np
13 | from scipy.io import loadmat
14 | from bbox import bbox_overlaps
15 | from IPython import embed
16 |
17 |
18 | def get_gt_boxes(gt_dir):
19 | """ gt dir: (wider_face_val.mat, wider_easy_val.mat, wider_medium_val.mat, wider_hard_val.mat)"""
20 |
21 | gt_mat = loadmat(os.path.join(gt_dir, 'wider_face_val.mat'))
22 | hard_mat = loadmat(os.path.join(gt_dir, 'wider_hard_val.mat'))
23 | medium_mat = loadmat(os.path.join(gt_dir, 'wider_medium_val.mat'))
24 | easy_mat = loadmat(os.path.join(gt_dir, 'wider_easy_val.mat'))
25 |
26 | facebox_list = gt_mat['face_bbx_list']
27 | event_list = gt_mat['event_list']
28 | file_list = gt_mat['file_list']
29 |
30 | hard_gt_list = hard_mat['gt_list']
31 | medium_gt_list = medium_mat['gt_list']
32 | easy_gt_list = easy_mat['gt_list']
33 |
34 | return facebox_list, event_list, file_list, hard_gt_list, medium_gt_list, easy_gt_list
35 |
36 |
37 | def get_gt_boxes_from_txt(gt_path, cache_dir):
38 |
39 | cache_file = os.path.join(cache_dir, 'gt_cache.pkl')
40 | if os.path.exists(cache_file):
41 | f = open(cache_file, 'rb')
42 | boxes = pickle.load(f)
43 | f.close()
44 | return boxes
45 |
46 | f = open(gt_path, 'r')
47 | state = 0
48 | lines = f.readlines()
49 | lines = list(map(lambda x: x.rstrip('\r\n'), lines))
50 | boxes = {}
51 | print(len(lines))
52 | f.close()
53 | current_boxes = []
54 | current_name = None
55 | for line in lines:
56 | if state == 0 and '--' in line:
57 | state = 1
58 | current_name = line
59 | continue
60 | if state == 1:
61 | state = 2
62 | continue
63 |
64 | if state == 2 and '--' in line:
65 | state = 1
66 | boxes[current_name] = np.array(current_boxes).astype('float32')
67 | current_name = line
68 | current_boxes = []
69 | continue
70 |
71 | if state == 2:
72 | box = [float(x) for x in line.split(' ')[:4]]
73 | current_boxes.append(box)
74 | continue
75 |
76 | f = open(cache_file, 'wb')
77 | pickle.dump(boxes, f)
78 | f.close()
79 | return boxes
80 |
81 |
82 | def read_pred_file(filepath):
83 |
84 | with open(filepath, 'r') as f:
85 | lines = f.readlines()
86 | img_file = lines[0].rstrip('\n\r')
87 | lines = lines[2:]
88 |
89 | # b = lines[0].rstrip('\r\n').split(' ')[:-1]
90 | # c = float(b)
91 | # a = map(lambda x: [[float(a[0]), float(a[1]), float(a[2]), float(a[3]), float(a[4])] for a in x.rstrip('\r\n').split(' ')], lines)
92 | boxes = []
93 | for line in lines:
94 | line = line.rstrip('\r\n').split(' ')
95 | if line[0] == '':
96 | continue
97 | # a = float(line[4])
98 | boxes.append([float(line[0]), float(line[1]), float(line[2]), float(line[3]), float(line[4])])
99 | boxes = np.array(boxes)
100 | # boxes = np.array(list(map(lambda x: [float(a) for a in x.rstrip('\r\n').split(' ')], lines))).astype('float')
101 | return img_file.split('/')[-1], boxes
102 |
103 |
104 | def get_preds(pred_dir):
105 | events = os.listdir(pred_dir)
106 | boxes = dict()
107 | pbar = tqdm.tqdm(events)
108 |
109 | for event in pbar:
110 | pbar.set_description('Reading Predictions ')
111 | event_dir = os.path.join(pred_dir, event)
112 | event_images = os.listdir(event_dir)
113 | current_event = dict()
114 | for imgtxt in event_images:
115 | imgname, _boxes = read_pred_file(os.path.join(event_dir, imgtxt))
116 | current_event[imgname.rstrip('.jpg')] = _boxes
117 | boxes[event] = current_event
118 | return boxes
119 |
120 |
121 | def norm_score(pred):
122 | """ norm score
123 | pred {key: [[x1,y1,x2,y2,s]]}
124 | """
125 |
126 | max_score = 0
127 | min_score = 1
128 |
129 | for _, k in pred.items():
130 | for _, v in k.items():
131 | if len(v) == 0:
132 | continue
133 | _min = np.min(v[:, -1])
134 | _max = np.max(v[:, -1])
135 | max_score = max(_max, max_score)
136 | min_score = min(_min, min_score)
137 |
138 | diff = max_score - min_score
139 | for _, k in pred.items():
140 | for _, v in k.items():
141 | if len(v) == 0:
142 | continue
143 | v[:, -1] = (v[:, -1] - min_score)/diff
144 |
145 |
146 | def image_eval(pred, gt, ignore, iou_thresh):
147 | """ single image evaluation
148 | pred: Nx5
149 | gt: Nx4
150 | ignore:
151 | """
152 |
153 | _pred = pred.copy()
154 | _gt = gt.copy()
155 | pred_recall = np.zeros(_pred.shape[0])
156 | recall_list = np.zeros(_gt.shape[0])
157 | proposal_list = np.ones(_pred.shape[0])
158 |
159 | _pred[:, 2] = _pred[:, 2] + _pred[:, 0]
160 | _pred[:, 3] = _pred[:, 3] + _pred[:, 1]
161 | _gt[:, 2] = _gt[:, 2] + _gt[:, 0]
162 | _gt[:, 3] = _gt[:, 3] + _gt[:, 1]
163 |
164 | overlaps = bbox_overlaps(_pred[:, :4], _gt)
165 |
166 | for h in range(_pred.shape[0]):
167 |
168 | gt_overlap = overlaps[h]
169 | max_overlap, max_idx = gt_overlap.max(), gt_overlap.argmax()
170 | if max_overlap >= iou_thresh:
171 | if ignore[max_idx] == 0:
172 | recall_list[max_idx] = -1
173 | proposal_list[h] = -1
174 | elif recall_list[max_idx] == 0:
175 | recall_list[max_idx] = 1
176 |
177 | r_keep_index = np.where(recall_list == 1)[0]
178 | pred_recall[h] = len(r_keep_index)
179 | return pred_recall, proposal_list
180 |
181 |
182 | def img_pr_info(thresh_num, pred_info, proposal_list, pred_recall):
183 | pr_info = np.zeros((thresh_num, 2)).astype('float')
184 | for t in range(thresh_num):
185 |
186 | thresh = 1 - (t+1)/thresh_num
187 | r_index = np.where(pred_info[:, 4] >= thresh)[0]
188 | if len(r_index) == 0:
189 | pr_info[t, 0] = 0
190 | pr_info[t, 1] = 0
191 | else:
192 | r_index = r_index[-1]
193 | p_index = np.where(proposal_list[:r_index+1] == 1)[0]
194 | pr_info[t, 0] = len(p_index)
195 | pr_info[t, 1] = pred_recall[r_index]
196 | return pr_info
197 |
198 |
199 | def dataset_pr_info(thresh_num, pr_curve, count_face):
200 | _pr_curve = np.zeros((thresh_num, 2))
201 | for i in range(thresh_num):
202 | _pr_curve[i, 0] = pr_curve[i, 1] / pr_curve[i, 0]
203 | _pr_curve[i, 1] = pr_curve[i, 1] / count_face
204 | return _pr_curve
205 |
206 |
207 | def voc_ap(rec, prec):
208 |
209 | # correct AP calculation
210 | # first append sentinel values at the end
211 | mrec = np.concatenate(([0.], rec, [1.]))
212 | mpre = np.concatenate(([0.], prec, [0.]))
213 |
214 | # compute the precision envelope
215 | for i in range(mpre.size - 1, 0, -1):
216 | mpre[i - 1] = np.maximum(mpre[i - 1], mpre[i])
217 |
218 | # to calculate area under PR curve, look for points
219 | # where X axis (recall) changes value
220 | i = np.where(mrec[1:] != mrec[:-1])[0]
221 |
222 | # and sum (\Delta recall) * prec
223 | ap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1])
224 | return ap
225 |
226 |
227 | def evaluation(pred, gt_path, iou_thresh=0.5):
228 | pred = get_preds(pred)
229 | norm_score(pred)
230 | facebox_list, event_list, file_list, hard_gt_list, medium_gt_list, easy_gt_list = get_gt_boxes(gt_path)
231 | event_num = len(event_list)
232 | thresh_num = 1000
233 | settings = ['easy', 'medium', 'hard']
234 | setting_gts = [easy_gt_list, medium_gt_list, hard_gt_list]
235 | aps = []
236 | for setting_id in range(3):
237 | # different setting
238 | gt_list = setting_gts[setting_id]
239 | count_face = 0
240 | pr_curve = np.zeros((thresh_num, 2)).astype('float')
241 | # [hard, medium, easy]
242 | pbar = tqdm.tqdm(range(event_num))
243 | for i in pbar:
244 | pbar.set_description('Processing {}'.format(settings[setting_id]))
245 | event_name = str(event_list[i][0][0])
246 | img_list = file_list[i][0]
247 | pred_list = pred[event_name]
248 | sub_gt_list = gt_list[i][0]
249 | # img_pr_info_list = np.zeros((len(img_list), thresh_num, 2))
250 | gt_bbx_list = facebox_list[i][0]
251 |
252 | for j in range(len(img_list)):
253 | pred_info = pred_list[str(img_list[j][0][0])]
254 |
255 | gt_boxes = gt_bbx_list[j][0].astype('float')
256 | keep_index = sub_gt_list[j][0]
257 | count_face += len(keep_index)
258 |
259 | if len(gt_boxes) == 0 or len(pred_info) == 0:
260 | continue
261 | ignore = np.zeros(gt_boxes.shape[0])
262 | if len(keep_index) != 0:
263 | ignore[keep_index-1] = 1
264 | pred_recall, proposal_list = image_eval(pred_info, gt_boxes, ignore, iou_thresh)
265 |
266 | _img_pr_info = img_pr_info(thresh_num, pred_info, proposal_list, pred_recall)
267 |
268 | pr_curve += _img_pr_info
269 | pr_curve = dataset_pr_info(thresh_num, pr_curve, count_face)
270 |
271 | propose = pr_curve[:, 0]
272 | recall = pr_curve[:, 1]
273 |
274 | ap = voc_ap(recall, propose)
275 | aps.append(ap)
276 |
277 | print("==================== Results ====================")
278 | print("Easy Val AP: {}".format(aps[0]))
279 | print("Medium Val AP: {}".format(aps[1]))
280 | print("Hard Val AP: {}".format(aps[2]))
281 | print("=================================================")
282 |
283 |
284 | if __name__ == '__main__':
285 |
286 | parser = argparse.ArgumentParser()
287 | parser.add_argument('-p', '--pred', default="./widerface_txt/")
288 | parser.add_argument('-g', '--gt', default='./ground_truth/')
289 |
290 | args = parser.parse_args()
291 | evaluation(args.pred, args.gt)
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
--------------------------------------------------------------------------------
/yolov5-face/widerface_evaluate/ground_truth/wider_easy_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IS2AI/AnyFace/bed844d23be03334f7fc12b2c4fb3ba2ac530bab/yolov5-face/widerface_evaluate/ground_truth/wider_easy_val.mat
--------------------------------------------------------------------------------
/yolov5-face/widerface_evaluate/ground_truth/wider_face_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IS2AI/AnyFace/bed844d23be03334f7fc12b2c4fb3ba2ac530bab/yolov5-face/widerface_evaluate/ground_truth/wider_face_val.mat
--------------------------------------------------------------------------------
/yolov5-face/widerface_evaluate/ground_truth/wider_hard_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IS2AI/AnyFace/bed844d23be03334f7fc12b2c4fb3ba2ac530bab/yolov5-face/widerface_evaluate/ground_truth/wider_hard_val.mat
--------------------------------------------------------------------------------
/yolov5-face/widerface_evaluate/ground_truth/wider_medium_val.mat:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IS2AI/AnyFace/bed844d23be03334f7fc12b2c4fb3ba2ac530bab/yolov5-face/widerface_evaluate/ground_truth/wider_medium_val.mat
--------------------------------------------------------------------------------
/yolov5-face/widerface_evaluate/setup.py:
--------------------------------------------------------------------------------
1 | """
2 | WiderFace evaluation code
3 | author: wondervictor
4 | mail: tianhengcheng@gmail.com
5 | copyright@wondervictor
6 | """
7 |
8 | from distutils.core import setup, Extension
9 | from Cython.Build import cythonize
10 | import numpy
11 |
12 | package = Extension('bbox', ['box_overlaps.pyx'], include_dirs=[numpy.get_include()])
13 | setup(ext_modules=cythonize([package]))
14 |
--------------------------------------------------------------------------------