├── .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 | 45 | 46 | 47 | 48 | 49 | 50 | 51 |
yolov5n-0.5yolov5n-face
52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 |
yolov5s-faceyolov5m-faceyolov5l-face
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 | 44 | 45 | 46 | 47 | 48 | 49 | 50 |
yolov5n-0.5yolov5n-face
51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 |
yolov5s-faceyolov5m-faceyolov5l-face
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 | --------------------------------------------------------------------------------