├── coco.names ├── data ├── coco.names ├── samples │ ├── dog.jpg │ ├── room.jpg │ ├── eagle.jpg │ ├── field.jpg │ ├── giraffe.jpg │ ├── messi.jpg │ ├── person.jpg │ ├── street.jpg │ └── herd_of_horses.jpg ├── ImageSets │ └── Main │ │ ├── val.txt │ │ ├── test.txt │ │ ├── trainval.txt │ │ └── train.txt ├── get_coco_dataset.sh └── label.py ├── custom ├── classes.names ├── train.txt ├── valid.txt ├── labels │ └── train.txt └── images │ └── train.jpg ├── assets ├── dog.png ├── messi.png ├── giraffe.png └── traffic.png ├── samples ├── dog.jpg ├── room.jpg ├── eagle.jpg ├── field.jpg ├── giraffe.jpg ├── messi.jpg ├── person.jpg ├── street.jpg └── herd_of_horses.jpg ├── config ├── custom.data ├── coco.data ├── yolov3-tiny.cfg ├── yolov3.cfg └── create_custom_model.sh ├── ImageSets └── Main │ ├── val.txt │ ├── test.txt │ ├── trainval.txt │ └── train.txt ├── requirements.txt ├── val.txt ├── utils ├── augmentations.py ├── logger.py ├── parse_config.py ├── datasets.py └── utils.py ├── weights └── download_weights.sh ├── get_coco_dataset.sh ├── label.py ├── test.txt ├── voc_annotation.py ├── .gitignore ├── README.md ├── test.py ├── detect.py ├── train.py ├── train.txt ├── models.py └── LICENSE /coco.names: -------------------------------------------------------------------------------- 1 | aircraft -------------------------------------------------------------------------------- /data/coco.names: -------------------------------------------------------------------------------- 1 | aircraft -------------------------------------------------------------------------------- /custom/classes.names: -------------------------------------------------------------------------------- 1 | aircraft -------------------------------------------------------------------------------- /custom/train.txt: -------------------------------------------------------------------------------- 1 | data/custom/images/train.jpg 2 | -------------------------------------------------------------------------------- /custom/valid.txt: -------------------------------------------------------------------------------- 1 | data/custom/images/train.jpg 2 | -------------------------------------------------------------------------------- /custom/labels/train.txt: -------------------------------------------------------------------------------- 1 | 0 0.515 0.5 0.21694873 0.18286777 2 | -------------------------------------------------------------------------------- /assets/dog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesjakeies/YOLOv3-Pytorch-better/HEAD/assets/dog.png -------------------------------------------------------------------------------- /assets/messi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesjakeies/YOLOv3-Pytorch-better/HEAD/assets/messi.png -------------------------------------------------------------------------------- /samples/dog.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesjakeies/YOLOv3-Pytorch-better/HEAD/samples/dog.jpg -------------------------------------------------------------------------------- /samples/room.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesjakeies/YOLOv3-Pytorch-better/HEAD/samples/room.jpg -------------------------------------------------------------------------------- /assets/giraffe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesjakeies/YOLOv3-Pytorch-better/HEAD/assets/giraffe.png -------------------------------------------------------------------------------- /assets/traffic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesjakeies/YOLOv3-Pytorch-better/HEAD/assets/traffic.png -------------------------------------------------------------------------------- /config/custom.data: -------------------------------------------------------------------------------- 1 | classes= 1 2 | train=train.txt 3 | valid=val.txt 4 | names=data/custom/classes.names 5 | -------------------------------------------------------------------------------- /samples/eagle.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesjakeies/YOLOv3-Pytorch-better/HEAD/samples/eagle.jpg -------------------------------------------------------------------------------- /samples/field.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesjakeies/YOLOv3-Pytorch-better/HEAD/samples/field.jpg -------------------------------------------------------------------------------- /samples/giraffe.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesjakeies/YOLOv3-Pytorch-better/HEAD/samples/giraffe.jpg -------------------------------------------------------------------------------- /samples/messi.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesjakeies/YOLOv3-Pytorch-better/HEAD/samples/messi.jpg -------------------------------------------------------------------------------- /samples/person.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesjakeies/YOLOv3-Pytorch-better/HEAD/samples/person.jpg -------------------------------------------------------------------------------- /samples/street.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesjakeies/YOLOv3-Pytorch-better/HEAD/samples/street.jpg -------------------------------------------------------------------------------- /ImageSets/Main/val.txt: -------------------------------------------------------------------------------- 1 | aircraft_1008 2 | aircraft_341 3 | aircraft_455 4 | aircraft_625 5 | aircraft_752 6 | -------------------------------------------------------------------------------- /data/samples/dog.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesjakeies/YOLOv3-Pytorch-better/HEAD/data/samples/dog.jpg -------------------------------------------------------------------------------- /data/samples/room.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesjakeies/YOLOv3-Pytorch-better/HEAD/data/samples/room.jpg -------------------------------------------------------------------------------- /custom/images/train.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesjakeies/YOLOv3-Pytorch-better/HEAD/custom/images/train.jpg -------------------------------------------------------------------------------- /data/ImageSets/Main/val.txt: -------------------------------------------------------------------------------- 1 | aircraft_1008 2 | aircraft_341 3 | aircraft_455 4 | aircraft_625 5 | aircraft_752 6 | -------------------------------------------------------------------------------- /data/samples/eagle.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesjakeies/YOLOv3-Pytorch-better/HEAD/data/samples/eagle.jpg -------------------------------------------------------------------------------- /data/samples/field.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesjakeies/YOLOv3-Pytorch-better/HEAD/data/samples/field.jpg -------------------------------------------------------------------------------- /data/samples/giraffe.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesjakeies/YOLOv3-Pytorch-better/HEAD/data/samples/giraffe.jpg -------------------------------------------------------------------------------- /data/samples/messi.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesjakeies/YOLOv3-Pytorch-better/HEAD/data/samples/messi.jpg -------------------------------------------------------------------------------- /data/samples/person.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesjakeies/YOLOv3-Pytorch-better/HEAD/data/samples/person.jpg -------------------------------------------------------------------------------- /data/samples/street.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesjakeies/YOLOv3-Pytorch-better/HEAD/data/samples/street.jpg -------------------------------------------------------------------------------- /samples/herd_of_horses.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesjakeies/YOLOv3-Pytorch-better/HEAD/samples/herd_of_horses.jpg -------------------------------------------------------------------------------- /data/samples/herd_of_horses.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesjakeies/YOLOv3-Pytorch-better/HEAD/data/samples/herd_of_horses.jpg -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | numpy 2 | torch>=1.0 3 | torchvision 4 | matplotlib 5 | tensorflow 6 | tensorboard 7 | terminaltables 8 | pillow 9 | tqdm 10 | -------------------------------------------------------------------------------- /config/coco.data: -------------------------------------------------------------------------------- 1 | classes= 80 2 | train=data/coco/trainvalno5k.txt 3 | valid=data/coco/5k.txt 4 | names=data/coco.names 5 | backup=backup/ 6 | eval=coco 7 | -------------------------------------------------------------------------------- /val.txt: -------------------------------------------------------------------------------- 1 | data/JPEGImages/aircraft_1008.jpg 2 | data/JPEGImages/aircraft_341.jpg 3 | data/JPEGImages/aircraft_455.jpg 4 | data/JPEGImages/aircraft_625.jpg 5 | data/JPEGImages/aircraft_752.jpg 6 | -------------------------------------------------------------------------------- /utils/augmentations.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn.functional as F 3 | import numpy as np 4 | 5 | 6 | def horisontal_flip(images, targets): 7 | images = torch.flip(images, [-1]) 8 | targets[:, 2] = 1 - targets[:, 2] 9 | return images, targets 10 | -------------------------------------------------------------------------------- /weights/download_weights.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Download weights for vanilla YOLOv3 3 | wget -c https://pjreddie.com/media/files/yolov3.weights 4 | # # Download weights for tiny YOLOv3 5 | wget -c https://pjreddie.com/media/files/yolov3-tiny.weights 6 | # Download weights for backbone network 7 | wget -c https://pjreddie.com/media/files/darknet53.conv.74 8 | -------------------------------------------------------------------------------- /ImageSets/Main/test.txt: -------------------------------------------------------------------------------- 1 | aircraft_1034 2 | aircraft_1045 3 | aircraft_1058 4 | aircraft_1072 5 | aircraft_1077 6 | aircraft_1136 7 | aircraft_148 8 | aircraft_186 9 | aircraft_200 10 | aircraft_217 11 | aircraft_251 12 | aircraft_252 13 | aircraft_261 14 | aircraft_281 15 | aircraft_303 16 | aircraft_326 17 | aircraft_376 18 | aircraft_407 19 | aircraft_443 20 | aircraft_448 21 | aircraft_475 22 | aircraft_513 23 | aircraft_573 24 | aircraft_594 25 | aircraft_635 26 | aircraft_642 27 | aircraft_671 28 | aircraft_674 29 | aircraft_760 30 | aircraft_764 31 | aircraft_819 32 | aircraft_886 33 | aircraft_891 34 | aircraft_893 35 | aircraft_934 36 | aircraft_944 37 | aircraft_955 38 | aircraft_971 39 | aircraft_988 40 | -------------------------------------------------------------------------------- /data/ImageSets/Main/test.txt: -------------------------------------------------------------------------------- 1 | aircraft_1034 2 | aircraft_1045 3 | aircraft_1058 4 | aircraft_1072 5 | aircraft_1077 6 | aircraft_1136 7 | aircraft_148 8 | aircraft_186 9 | aircraft_200 10 | aircraft_217 11 | aircraft_251 12 | aircraft_252 13 | aircraft_261 14 | aircraft_281 15 | aircraft_303 16 | aircraft_326 17 | aircraft_376 18 | aircraft_407 19 | aircraft_443 20 | aircraft_448 21 | aircraft_475 22 | aircraft_513 23 | aircraft_573 24 | aircraft_594 25 | aircraft_635 26 | aircraft_642 27 | aircraft_671 28 | aircraft_674 29 | aircraft_760 30 | aircraft_764 31 | aircraft_819 32 | aircraft_886 33 | aircraft_891 34 | aircraft_893 35 | aircraft_934 36 | aircraft_944 37 | aircraft_955 38 | aircraft_971 39 | aircraft_988 40 | -------------------------------------------------------------------------------- /utils/logger.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | 3 | 4 | class Logger(object): 5 | def __init__(self, log_dir): 6 | """Create a summary writer logging to log_dir.""" 7 | self.writer = tf.summary.FileWriter(log_dir) 8 | 9 | def scalar_summary(self, tag, value, step): 10 | """Log a scalar variable.""" 11 | summary = tf.Summary(value=[tf.Summary.Value(tag=tag, simple_value=value)]) 12 | self.writer.add_summary(summary, step) 13 | 14 | def list_of_scalars_summary(self, tag_value_pairs, step): 15 | """Log scalar variables.""" 16 | summary = tf.Summary(value=[tf.Summary.Value(tag=tag, simple_value=value) for tag, value in tag_value_pairs]) 17 | self.writer.add_summary(summary, step) 18 | -------------------------------------------------------------------------------- /ImageSets/Main/trainval.txt: -------------------------------------------------------------------------------- 1 | aircraft_1008 2 | aircraft_1034 3 | aircraft_1045 4 | aircraft_1058 5 | aircraft_1072 6 | aircraft_1077 7 | aircraft_1136 8 | aircraft_148 9 | aircraft_186 10 | aircraft_200 11 | aircraft_217 12 | aircraft_251 13 | aircraft_252 14 | aircraft_261 15 | aircraft_281 16 | aircraft_303 17 | aircraft_326 18 | aircraft_341 19 | aircraft_376 20 | aircraft_407 21 | aircraft_443 22 | aircraft_448 23 | aircraft_455 24 | aircraft_475 25 | aircraft_513 26 | aircraft_573 27 | aircraft_594 28 | aircraft_625 29 | aircraft_635 30 | aircraft_642 31 | aircraft_671 32 | aircraft_674 33 | aircraft_752 34 | aircraft_760 35 | aircraft_764 36 | aircraft_819 37 | aircraft_886 38 | aircraft_891 39 | aircraft_893 40 | aircraft_934 41 | aircraft_944 42 | aircraft_955 43 | aircraft_971 44 | aircraft_988 45 | -------------------------------------------------------------------------------- /data/ImageSets/Main/trainval.txt: -------------------------------------------------------------------------------- 1 | aircraft_1008 2 | aircraft_1034 3 | aircraft_1045 4 | aircraft_1058 5 | aircraft_1072 6 | aircraft_1077 7 | aircraft_1136 8 | aircraft_148 9 | aircraft_186 10 | aircraft_200 11 | aircraft_217 12 | aircraft_251 13 | aircraft_252 14 | aircraft_261 15 | aircraft_281 16 | aircraft_303 17 | aircraft_326 18 | aircraft_341 19 | aircraft_376 20 | aircraft_407 21 | aircraft_443 22 | aircraft_448 23 | aircraft_455 24 | aircraft_475 25 | aircraft_513 26 | aircraft_573 27 | aircraft_594 28 | aircraft_625 29 | aircraft_635 30 | aircraft_642 31 | aircraft_671 32 | aircraft_674 33 | aircraft_752 34 | aircraft_760 35 | aircraft_764 36 | aircraft_819 37 | aircraft_886 38 | aircraft_891 39 | aircraft_893 40 | aircraft_934 41 | aircraft_944 42 | aircraft_955 43 | aircraft_971 44 | aircraft_988 45 | -------------------------------------------------------------------------------- /get_coco_dataset.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # CREDIT: https://github.com/pjreddie/darknet/tree/master/scripts/get_coco_dataset.sh 4 | 5 | # Clone COCO API 6 | git clone https://github.com/pdollar/coco 7 | cd coco 8 | 9 | mkdir images 10 | cd images 11 | 12 | # Download Images 13 | wget -c https://pjreddie.com/media/files/train2014.zip 14 | wget -c https://pjreddie.com/media/files/val2014.zip 15 | 16 | # Unzip 17 | unzip -q train2014.zip 18 | unzip -q val2014.zip 19 | 20 | cd .. 21 | 22 | # Download COCO Metadata 23 | wget -c https://pjreddie.com/media/files/instances_train-val2014.zip 24 | wget -c https://pjreddie.com/media/files/coco/5k.part 25 | wget -c https://pjreddie.com/media/files/coco/trainvalno5k.part 26 | wget -c https://pjreddie.com/media/files/coco/labels.tgz 27 | tar xzf labels.tgz 28 | unzip -q instances_train-val2014.zip 29 | 30 | # Set Up Image Lists 31 | paste <(awk "{print \"$PWD\"}" <5k.part) 5k.part | tr -d '\t' > 5k.txt 32 | paste <(awk "{print \"$PWD\"}" trainvalno5k.txt 33 | -------------------------------------------------------------------------------- /data/get_coco_dataset.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # CREDIT: https://github.com/pjreddie/darknet/tree/master/scripts/get_coco_dataset.sh 4 | 5 | # Clone COCO API 6 | git clone https://github.com/pdollar/coco 7 | cd coco 8 | 9 | mkdir images 10 | cd images 11 | 12 | # Download Images 13 | wget -c https://pjreddie.com/media/files/train2014.zip 14 | wget -c https://pjreddie.com/media/files/val2014.zip 15 | 16 | # Unzip 17 | unzip -q train2014.zip 18 | unzip -q val2014.zip 19 | 20 | cd .. 21 | 22 | # Download COCO Metadata 23 | wget -c https://pjreddie.com/media/files/instances_train-val2014.zip 24 | wget -c https://pjreddie.com/media/files/coco/5k.part 25 | wget -c https://pjreddie.com/media/files/coco/trainvalno5k.part 26 | wget -c https://pjreddie.com/media/files/coco/labels.tgz 27 | tar xzf labels.tgz 28 | unzip -q instances_train-val2014.zip 29 | 30 | # Set Up Image Lists 31 | paste <(awk "{print \"$PWD\"}" <5k.part) 5k.part | tr -d '\t' > 5k.txt 32 | paste <(awk "{print \"$PWD\"}" trainvalno5k.txt 33 | -------------------------------------------------------------------------------- /label.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import random 4 | 5 | trainval_percent = 0.1 6 | 7 | train_percent = 0.9 8 | 9 | xmlfilepath = 'Annotations/xml' 10 | 11 | txtsavepath = 'ImageSets/Main' 12 | 13 | total_xml = os.listdir(xmlfilepath) 14 | 15 | num = len(total_xml) 16 | 17 | list = range(num) 18 | 19 | tv = int(num * trainval_percent) 20 | 21 | tr = int(tv * train_percent) 22 | 23 | trainval = random.sample(list, tv) 24 | 25 | train = random.sample(trainval, tr) 26 | 27 | ftrainval = open('ImageSets/Main/trainval.txt', 'w') 28 | 29 | ftest = open('ImageSets/Main/test.txt', 'w') 30 | 31 | ftrain = open('ImageSets/Main/train.txt', 'w') 32 | 33 | fval = open('ImageSets/Main/val.txt', 'w') 34 | 35 | for i in list: 36 | 37 | name = total_xml[i][:-4] + '\n' 38 | 39 | if i in trainval: 40 | 41 | ftrainval.write(name) 42 | 43 | if i in train: 44 | 45 | ftest.write(name) 46 | 47 | else: 48 | 49 | fval.write(name) 50 | 51 | else: 52 | 53 | ftrain.write(name) 54 | 55 | ftrainval.close() 56 | 57 | ftrain.close() 58 | 59 | fval.close() 60 | 61 | ftest.close() -------------------------------------------------------------------------------- /data/label.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import random 4 | 5 | trainval_percent = 0.1 6 | 7 | train_percent = 0.9 8 | 9 | xmlfilepath = 'Annotations/xml' 10 | 11 | txtsavepath = 'ImageSets/Main' 12 | 13 | total_xml = os.listdir(xmlfilepath) 14 | 15 | num = len(total_xml) 16 | 17 | list = range(num) 18 | 19 | tv = int(num * trainval_percent) 20 | 21 | tr = int(tv * train_percent) 22 | 23 | trainval = random.sample(list, tv) 24 | 25 | train = random.sample(trainval, tr) 26 | 27 | ftrainval = open('ImageSets/Main/trainval.txt', 'w') 28 | 29 | ftest = open('ImageSets/Main/test.txt', 'w') 30 | 31 | ftrain = open('ImageSets/Main/train.txt', 'w') 32 | 33 | fval = open('ImageSets/Main/val.txt', 'w') 34 | 35 | for i in list: 36 | 37 | name = total_xml[i][:-4] + '\n' 38 | 39 | if i in trainval: 40 | 41 | ftrainval.write(name) 42 | 43 | if i in train: 44 | 45 | ftest.write(name) 46 | 47 | else: 48 | 49 | fval.write(name) 50 | 51 | else: 52 | 53 | ftrain.write(name) 54 | 55 | ftrainval.close() 56 | 57 | ftrain.close() 58 | 59 | fval.close() 60 | 61 | ftest.close() -------------------------------------------------------------------------------- /utils/parse_config.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | def parse_model_config(path): 4 | """Parses the yolo-v3 layer configuration file and returns module definitions""" 5 | file = open(path, 'r') 6 | lines = file.read().split('\n') 7 | lines = [x for x in lines if x and not x.startswith('#')] 8 | lines = [x.rstrip().lstrip() for x in lines] # get rid of fringe whitespaces 9 | module_defs = [] 10 | for line in lines: 11 | if line.startswith('['): # This marks the start of a new block 12 | module_defs.append({}) 13 | module_defs[-1]['type'] = line[1:-1].rstrip() 14 | if module_defs[-1]['type'] == 'convolutional': 15 | module_defs[-1]['batch_normalize'] = 0 16 | else: 17 | key, value = line.split("=") 18 | value = value.strip() 19 | module_defs[-1][key.rstrip()] = value.strip() 20 | 21 | return module_defs 22 | 23 | def parse_data_config(path): 24 | """Parses the data configuration file""" 25 | options = dict() 26 | options['gpus'] = '0,1,2,3' 27 | options['num_workers'] = '10' 28 | with open(path, 'r') as fp: 29 | lines = fp.readlines() 30 | for line in lines: 31 | line = line.strip() 32 | if line == '' or line.startswith('#'): 33 | continue 34 | key, value = line.split('=') 35 | options[key.strip()] = value.strip() 36 | return options 37 | -------------------------------------------------------------------------------- /test.txt: -------------------------------------------------------------------------------- 1 | data/JPEGImages/aircraft_1034.jpg 2 | data/JPEGImages/aircraft_1045.jpg 3 | data/JPEGImages/aircraft_1058.jpg 4 | data/JPEGImages/aircraft_1072.jpg 5 | data/JPEGImages/aircraft_1077.jpg 6 | data/JPEGImages/aircraft_1136.jpg 7 | data/JPEGImages/aircraft_148.jpg 8 | data/JPEGImages/aircraft_186.jpg 9 | data/JPEGImages/aircraft_200.jpg 10 | data/JPEGImages/aircraft_217.jpg 11 | data/JPEGImages/aircraft_251.jpg 12 | data/JPEGImages/aircraft_252.jpg 13 | data/JPEGImages/aircraft_261.jpg 14 | data/JPEGImages/aircraft_281.jpg 15 | data/JPEGImages/aircraft_303.jpg 16 | data/JPEGImages/aircraft_326.jpg 17 | data/JPEGImages/aircraft_376.jpg 18 | data/JPEGImages/aircraft_407.jpg 19 | data/JPEGImages/aircraft_443.jpg 20 | data/JPEGImages/aircraft_448.jpg 21 | data/JPEGImages/aircraft_475.jpg 22 | data/JPEGImages/aircraft_513.jpg 23 | data/JPEGImages/aircraft_573.jpg 24 | data/JPEGImages/aircraft_594.jpg 25 | data/JPEGImages/aircraft_635.jpg 26 | data/JPEGImages/aircraft_642.jpg 27 | data/JPEGImages/aircraft_671.jpg 28 | data/JPEGImages/aircraft_674.jpg 29 | data/JPEGImages/aircraft_760.jpg 30 | data/JPEGImages/aircraft_764.jpg 31 | data/JPEGImages/aircraft_819.jpg 32 | data/JPEGImages/aircraft_886.jpg 33 | data/JPEGImages/aircraft_891.jpg 34 | data/JPEGImages/aircraft_893.jpg 35 | data/JPEGImages/aircraft_934.jpg 36 | data/JPEGImages/aircraft_944.jpg 37 | data/JPEGImages/aircraft_955.jpg 38 | data/JPEGImages/aircraft_971.jpg 39 | data/JPEGImages/aircraft_988.jpg 40 | -------------------------------------------------------------------------------- /voc_annotation.py: -------------------------------------------------------------------------------- 1 | import xml.etree.ElementTree as ET 2 | 3 | import pickle 4 | 5 | import os 6 | 7 | from os import listdir, getcwd 8 | 9 | from os.path import join 10 | 11 | sets = ['train', 'test', 'val'] 12 | 13 | classes = ["aircraft"] # 我们只是检测细胞,因此只有一个类别 14 | 15 | 16 | def convert(size, box): 17 | dw = 1. / size[0] 18 | 19 | dh = 1. / size[1] 20 | 21 | x = (box[0] + box[1]) / 2.0 22 | 23 | y = (box[2] + box[3]) / 2.0 24 | 25 | w = box[1] - box[0] 26 | 27 | h = box[3] - box[2] 28 | 29 | x = x * dw 30 | 31 | w = w * dw 32 | 33 | y = y * dh 34 | 35 | h = h * dh 36 | 37 | return (x, y, w, h) 38 | 39 | 40 | def convert_annotation(image_id): 41 | in_file = open('data/Annotations/xml/%s.xml' % (image_id)) 42 | 43 | out_file = open('data/labels/%s.txt' % (image_id), 'w') 44 | 45 | tree = ET.parse(in_file) 46 | 47 | root = tree.getroot() 48 | 49 | size = root.find('size') 50 | 51 | w = int(size.find('width').text) 52 | 53 | h = int(size.find('height').text) 54 | 55 | for obj in root.iter('object'): 56 | 57 | difficult = obj.find('difficult').text 58 | 59 | cls = obj.find('name').text 60 | 61 | if cls not in classes or int(difficult) == 1: 62 | continue 63 | 64 | cls_id = classes.index(cls) 65 | 66 | xmlbox = obj.find('bndbox') 67 | 68 | b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text), 69 | 70 | float(xmlbox.find('ymax').text)) 71 | 72 | bb = convert((w, h), b) 73 | 74 | out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n') 75 | 76 | 77 | wd = getcwd() 78 | 79 | print(wd) 80 | 81 | for image_set in sets: 82 | 83 | if not os.path.exists('data/labels/'): 84 | os.makedirs('data/labels/') 85 | 86 | image_ids = open('data/ImageSets/Main/%s.txt' % (image_set)).read().strip().split() 87 | 88 | list_file = open('%s.txt' % (image_set), 'w') 89 | 90 | for image_id in image_ids: 91 | list_file.write('data/JPEGImages/%s.jpg\n' % (image_id)) 92 | 93 | convert_annotation(image_id) 94 | 95 | list_file.close() -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # YOLOv3 by Pytorch 2 | 3 | 4 | ## Train 5 | ``` 6 | $ train.py [-h] [--epochs EPOCHS] [--batch_size BATCH_SIZE] 7 | [--gradient_accumulations GRADIENT_ACCUMULATIONS] 8 | [--model_def MODEL_DEF] [--data_config DATA_CONFIG] 9 | [--pretrained_weights PRETRAINED_WEIGHTS] [--n_cpu N_CPU] 10 | [--img_size IMG_SIZE] 11 | [--checkpoint_interval CHECKPOINT_INTERVAL] 12 | [--evaluation_interval EVALUATION_INTERVAL] 13 | [--compute_map COMPUTE_MAP] 14 | [--multiscale_training MULTISCALE_TRAINING] 15 | ``` 16 | 17 | #### Example (COCO) 18 | To train on COCO using a Darknet-53 backend pretrained on ImageNet run: 19 | ``` 20 | $ python3 train.py --data_config config/coco.data --pretrained_weights weights/darknet53.conv.74 21 | ``` 22 | 23 | #### Training log 24 | ``` 25 | ---- [Epoch 7/100, Batch 7300/14658] ---- 26 | +------------+--------------+--------------+--------------+ 27 | | Metrics | YOLO Layer 0 | YOLO Layer 1 | YOLO Layer 2 | 28 | +------------+--------------+--------------+--------------+ 29 | | grid_size | 16 | 32 | 64 | 30 | | loss | 1.554926 | 1.446884 | 1.427585 | 31 | | x | 0.028157 | 0.044483 | 0.051159 | 32 | | y | 0.040524 | 0.035687 | 0.046307 | 33 | | w | 0.078980 | 0.066310 | 0.027984 | 34 | | h | 0.133414 | 0.094540 | 0.037121 | 35 | | conf | 1.234448 | 1.165665 | 1.223495 | 36 | | cls | 0.039402 | 0.040198 | 0.041520 | 37 | | cls_acc | 44.44% | 43.59% | 32.50% | 38 | | recall50 | 0.361111 | 0.384615 | 0.300000 | 39 | | recall75 | 0.222222 | 0.282051 | 0.300000 | 40 | | precision | 0.520000 | 0.300000 | 0.070175 | 41 | | conf_obj | 0.599058 | 0.622685 | 0.651472 | 42 | | conf_noobj | 0.003778 | 0.004039 | 0.004044 | 43 | +------------+--------------+--------------+--------------+ 44 | Total Loss 4.429395 45 | ---- ETA 0:35:48.821929 46 | ``` 47 | 48 | #### Tensorboard 49 | Track training progress in Tensorboard: 50 | * Initialize training 51 | * Run the command below 52 | * Go to http://localhost:6006/ 53 | 54 | ``` 55 | $ tensorboard --logdir='logs' --port=6006 56 | ``` 57 | ## Train on VOC custom datasets 58 | ####you should create three Directories in Directory 'data' 59 | ``` 60 | $----data 61 | --Annotations 62 | --ImageSets 63 | --JPEGImages 64 | ``` 65 | If you wanna use the custom dataset of VOC,please set up you classes what u want to train,just as: 66 | from the path 67 | ``` 68 | data\custom 69 | 70 | ``` 71 | you can look a file named 'class.names ' 72 | 73 | click the file 74 | 75 | write you class on the file, just as 76 | 77 | ``` 78 | aircraft 79 | 80 | ``` 81 | ``` 82 | Run 83 | $ cd data 84 | $ python label.py 85 | $ cd .. 86 | $ python voc_annotation.py 87 | ``` 88 | 89 | #### Train 90 | To train on the custom dataset run: 91 | 92 | ``` 93 | $ python train.py --model_def config/yolov3-tiny.cfg --data_config config/custom.data --python train.py --pretrained_weights weights/yolov3-tiny.conv.15 94 | ``` 95 | 96 | Add `--pretrained_weights weights/darknet53.conv.74` to train using a backend pretrained on ImageNet. 97 | 98 | 99 | -------------------------------------------------------------------------------- /config/yolov3-tiny.cfg: -------------------------------------------------------------------------------- 1 | [net] 2 | # Testing 3 | batch=1 4 | subdivisions=1 5 | # Training 6 | # batch=64 7 | # subdivisions=2 8 | width=416 9 | height=416 10 | channels=3 11 | momentum=0.9 12 | decay=0.0005 13 | angle=0 14 | saturation = 1.5 15 | exposure = 1.5 16 | hue=.1 17 | 18 | learning_rate=0.001 19 | burn_in=1000 20 | max_batches = 500200 21 | policy=steps 22 | steps=400000,450000 23 | scales=.1,.1 24 | 25 | # 0 26 | [convolutional] 27 | batch_normalize=1 28 | filters=16 29 | size=3 30 | stride=1 31 | pad=1 32 | activation=leaky 33 | 34 | # 1 35 | [maxpool] 36 | size=2 37 | stride=2 38 | 39 | # 2 40 | [convolutional] 41 | batch_normalize=1 42 | filters=32 43 | size=3 44 | stride=1 45 | pad=1 46 | activation=leaky 47 | 48 | # 3 49 | [maxpool] 50 | size=2 51 | stride=2 52 | 53 | # 4 54 | [convolutional] 55 | batch_normalize=1 56 | filters=64 57 | size=3 58 | stride=1 59 | pad=1 60 | activation=leaky 61 | 62 | # 5 63 | [maxpool] 64 | size=2 65 | stride=2 66 | 67 | # 6 68 | [convolutional] 69 | batch_normalize=1 70 | filters=128 71 | size=3 72 | stride=1 73 | pad=1 74 | activation=leaky 75 | 76 | # 7 77 | [maxpool] 78 | size=2 79 | stride=2 80 | 81 | # 8 82 | [convolutional] 83 | batch_normalize=1 84 | filters=256 85 | size=3 86 | stride=1 87 | pad=1 88 | activation=leaky 89 | 90 | # 9 91 | [maxpool] 92 | size=2 93 | stride=2 94 | 95 | # 10 96 | [convolutional] 97 | batch_normalize=1 98 | filters=512 99 | size=3 100 | stride=1 101 | pad=1 102 | activation=leaky 103 | 104 | # 11 105 | [maxpool] 106 | size=2 107 | stride=1 108 | 109 | # 12 110 | [convolutional] 111 | batch_normalize=1 112 | filters=1024 113 | size=3 114 | stride=1 115 | pad=1 116 | activation=leaky 117 | 118 | ########### 119 | 120 | # 13 121 | [convolutional] 122 | batch_normalize=1 123 | filters=256 124 | size=1 125 | stride=1 126 | pad=1 127 | activation=leaky 128 | 129 | # 14 130 | [convolutional] 131 | batch_normalize=1 132 | filters=512 133 | size=3 134 | stride=1 135 | pad=1 136 | activation=leaky 137 | 138 | # 15 139 | [convolutional] 140 | size=1 141 | stride=1 142 | pad=1 143 | filters=6 144 | activation=linear 145 | 146 | 147 | 148 | # 16 149 | [yolo] 150 | mask = 3,4,5 151 | anchors = 10,14, 23,27, 37,58, 81,82, 135,169, 344,319 152 | classes=1 153 | num=6 154 | jitter=.3 155 | ignore_thresh = .7 156 | truth_thresh = 1 157 | random=1 158 | 159 | # 17 160 | [route] 161 | layers = -4 162 | 163 | # 18 164 | [convolutional] 165 | batch_normalize=1 166 | filters=128 167 | size=1 168 | stride=1 169 | pad=1 170 | activation=leaky 171 | 172 | # 19 173 | [upsample] 174 | stride=2 175 | 176 | # 20 177 | [route] 178 | layers = -1, 8 179 | 180 | # 21 181 | [convolutional] 182 | batch_normalize=1 183 | filters=256 184 | size=3 185 | stride=1 186 | pad=1 187 | activation=leaky 188 | 189 | # 22 190 | [convolutional] 191 | size=1 192 | stride=1 193 | pad=1 194 | filters=6 195 | activation=linear 196 | 197 | # 23 198 | [yolo] 199 | mask = 1,2,3 200 | anchors = 10,14, 23,27, 37,58, 81,82, 135,169, 344,319 201 | classes=1 202 | num=6 203 | jitter=.3 204 | ignore_thresh = .7 205 | truth_thresh = 1 206 | random=1 207 | -------------------------------------------------------------------------------- /test.py: -------------------------------------------------------------------------------- 1 | from __future__ import division 2 | 3 | from models import * 4 | from utils.utils import * 5 | from utils.datasets import * 6 | from utils.parse_config import * 7 | 8 | import os 9 | import sys 10 | import time 11 | import datetime 12 | import argparse 13 | import tqdm 14 | 15 | import torch 16 | from torch.utils.data import DataLoader 17 | from torchvision import datasets 18 | from torchvision import transforms 19 | from torch.autograd import Variable 20 | import torch.optim as optim 21 | 22 | 23 | def evaluate(model, path, iou_thres, conf_thres, nms_thres, img_size, batch_size): 24 | model.eval() 25 | 26 | # Get dataloader 27 | dataset = ListDataset(path, img_size=img_size, augment=False, multiscale=False) 28 | dataloader = torch.utils.data.DataLoader( 29 | dataset, batch_size=batch_size, shuffle=False, num_workers=1, collate_fn=dataset.collate_fn 30 | ) 31 | 32 | Tensor = torch.cuda.FloatTensor if torch.cuda.is_available() else torch.FloatTensor 33 | 34 | labels = [] 35 | sample_metrics = [] # List of tuples (TP, confs, pred) 36 | for batch_i, (_, imgs, targets) in enumerate(tqdm.tqdm(dataloader, desc="Detecting objects")): 37 | 38 | # Extract labels 39 | labels += targets[:, 1].tolist() 40 | # Rescale target 41 | targets[:, 2:] = xywh2xyxy(targets[:, 2:]) 42 | targets[:, 2:] *= img_size 43 | 44 | imgs = Variable(imgs.type(Tensor), requires_grad=False) 45 | 46 | with torch.no_grad(): 47 | outputs = model(imgs) 48 | outputs = non_max_suppression(outputs, conf_thres=conf_thres, nms_thres=nms_thres) 49 | 50 | sample_metrics += get_batch_statistics(outputs, targets, iou_threshold=iou_thres) 51 | 52 | # Concatenate sample statistics 53 | true_positives, pred_scores, pred_labels = [np.concatenate(x, 0) for x in list(zip(*sample_metrics))] 54 | precision, recall, AP, f1, ap_class = ap_per_class(true_positives, pred_scores, pred_labels, labels) 55 | 56 | return precision, recall, AP, f1, ap_class 57 | 58 | 59 | if __name__ == "__main__": 60 | parser = argparse.ArgumentParser() 61 | parser.add_argument("--batch_size", type=int, default=8, help="size of each image batch") 62 | parser.add_argument("--model_def", type=str, default="config/yolov3.cfg", help="path to model definition file") 63 | parser.add_argument("--data_config", type=str, default="config/coco.data", help="path to data config file") 64 | parser.add_argument("--weights_path", type=str, default="weights/yolov3.weights", help="path to weights file") 65 | parser.add_argument("--class_path", type=str, default="data/coco.names", help="path to class label file") 66 | parser.add_argument("--iou_thres", type=float, default=0.5, help="iou threshold required to qualify as detected") 67 | parser.add_argument("--conf_thres", type=float, default=0.001, help="object confidence threshold") 68 | parser.add_argument("--nms_thres", type=float, default=0.5, help="iou thresshold for non-maximum suppression") 69 | parser.add_argument("--n_cpu", type=int, default=8, help="number of cpu threads to use during batch generation") 70 | parser.add_argument("--img_size", type=int, default=416, help="size of each image dimension") 71 | opt = parser.parse_args() 72 | print(opt) 73 | 74 | device = torch.device("cuda" if torch.cuda.is_available() else "cpu") 75 | 76 | data_config = parse_data_config(opt.data_config) 77 | valid_path = data_config["valid"] 78 | class_names = load_classes(data_config["names"]) 79 | 80 | # Initiate model 81 | model = Darknet(opt.model_def).to(device) 82 | if opt.weights_path.endswith(".weights"): 83 | # Load darknet weights 84 | model.load_darknet_weights(opt.weights_path) 85 | else: 86 | # Load checkpoint weights 87 | model.load_state_dict(torch.load(opt.weights_path)) 88 | 89 | print("Compute mAP...") 90 | 91 | precision, recall, AP, f1, ap_class = evaluate( 92 | model, 93 | path=valid_path, 94 | iou_thres=opt.iou_thres, 95 | conf_thres=opt.conf_thres, 96 | nms_thres=opt.nms_thres, 97 | img_size=opt.img_size, 98 | batch_size=8, 99 | ) 100 | 101 | print("Average Precisions:") 102 | for i, c in enumerate(ap_class): 103 | print(f"+ Class '{c}' ({class_names[c]}) - AP: {AP[i]}") 104 | 105 | print(f"mAP: {AP.mean()}") 106 | -------------------------------------------------------------------------------- /utils/datasets.py: -------------------------------------------------------------------------------- 1 | import glob 2 | import random 3 | import os 4 | import sys 5 | import numpy as np 6 | from PIL import Image 7 | import torch 8 | import torch.nn.functional as F 9 | 10 | from utils.augmentations import horisontal_flip 11 | from torch.utils.data import Dataset 12 | import torchvision.transforms as transforms 13 | 14 | 15 | def pad_to_square(img, pad_value): 16 | c, h, w = img.shape 17 | dim_diff = np.abs(h - w) 18 | # (upper / left) padding and (lower / right) padding 19 | pad1, pad2 = dim_diff // 2, dim_diff - dim_diff // 2 20 | # Determine padding 21 | pad = (0, 0, pad1, pad2) if h <= w else (pad1, pad2, 0, 0) 22 | # Add padding 23 | img = F.pad(img, pad, "constant", value=pad_value) 24 | 25 | return img, pad 26 | 27 | 28 | def resize(image, size): 29 | image = F.interpolate(image.unsqueeze(0), size=size, mode="nearest").squeeze(0) 30 | return image 31 | 32 | 33 | def random_resize(images, min_size=288, max_size=448): 34 | new_size = random.sample(list(range(min_size, max_size + 1, 32)), 1)[0] 35 | images = F.interpolate(images, size=new_size, mode="nearest") 36 | return images 37 | 38 | 39 | class ImageFolder(Dataset): 40 | def __init__(self, folder_path, img_size=416): 41 | self.files = sorted(glob.glob("%s/*.*" % folder_path)) 42 | self.img_size = img_size 43 | 44 | def __getitem__(self, index): 45 | img_path = self.files[index % len(self.files)] 46 | # Extract image as PyTorch tensor 47 | img = transforms.ToTensor()(Image.open(img_path)) 48 | # Pad to square resolution 49 | img, _ = pad_to_square(img, 0) 50 | # Resize 51 | img = resize(img, self.img_size) 52 | 53 | return img_path, img 54 | 55 | def __len__(self): 56 | return len(self.files) 57 | 58 | 59 | class ListDataset(Dataset): 60 | def __init__(self, list_path, img_size=416, augment=True, multiscale=True, normalized_labels=True): 61 | with open(list_path, "r") as file: 62 | self.img_files = file.readlines() 63 | 64 | self.label_files = [ 65 | path.replace("images", "labels").replace(".png", ".txt").replace(".jpg", ".txt") 66 | for path in self.img_files 67 | ] 68 | self.img_size = img_size 69 | self.max_objects = 100 70 | self.augment = augment 71 | self.multiscale = multiscale 72 | self.normalized_labels = normalized_labels 73 | self.min_size = self.img_size - 3 * 32 74 | self.max_size = self.img_size + 3 * 32 75 | self.batch_count = 0 76 | 77 | def __getitem__(self, index): 78 | 79 | # --------- 80 | # Image 81 | # --------- 82 | 83 | img_path = self.img_files[index % len(self.img_files)].rstrip() 84 | 85 | # Extract image as PyTorch tensor 86 | img = transforms.ToTensor()(Image.open(img_path).convert('RGB')) 87 | 88 | # Handle images with less than three channels 89 | if len(img.shape) != 3: 90 | img = img.unsqueeze(0) 91 | img = img.expand((3, img.shape[1:])) 92 | 93 | _, h, w = img.shape 94 | h_factor, w_factor = (h, w) if self.normalized_labels else (1, 1) 95 | # Pad to square resolution 96 | img, pad = pad_to_square(img, 0) 97 | _, padded_h, padded_w = img.shape 98 | 99 | # --------- 100 | # Label 101 | # --------- 102 | 103 | label_path = self.label_files[index % len(self.img_files)].rstrip() 104 | 105 | targets = None 106 | if os.path.exists(label_path): 107 | boxes = torch.from_numpy(np.loadtxt(label_path).reshape(-1, 5)) 108 | # Extract coordinates for unpadded + unscaled image 109 | x1 = w_factor * (boxes[:, 1] - boxes[:, 3] / 2) 110 | y1 = h_factor * (boxes[:, 2] - boxes[:, 4] / 2) 111 | x2 = w_factor * (boxes[:, 1] + boxes[:, 3] / 2) 112 | y2 = h_factor * (boxes[:, 2] + boxes[:, 4] / 2) 113 | # Adjust for added padding 114 | x1 += pad[0] 115 | y1 += pad[2] 116 | x2 += pad[1] 117 | y2 += pad[3] 118 | # Returns (x, y, w, h) 119 | boxes[:, 1] = ((x1 + x2) / 2) / padded_w 120 | boxes[:, 2] = ((y1 + y2) / 2) / padded_h 121 | boxes[:, 3] *= w_factor / padded_w 122 | boxes[:, 4] *= h_factor / padded_h 123 | 124 | targets = torch.zeros((len(boxes), 6)) 125 | targets[:, 1:] = boxes 126 | 127 | # Apply augmentations 128 | if self.augment: 129 | if np.random.random() < 0.5: 130 | img, targets = horisontal_flip(img, targets) 131 | 132 | return img_path, img, targets 133 | 134 | def collate_fn(self, batch): 135 | paths, imgs, targets = list(zip(*batch)) 136 | # Remove empty placeholder targets 137 | targets = [boxes for boxes in targets if boxes is not None] 138 | # Add sample index to targets 139 | for i, boxes in enumerate(targets): 140 | boxes[:, 0] = i 141 | targets = torch.cat(targets, 0) 142 | # Selects new image size every tenth batch 143 | if self.multiscale and self.batch_count % 10 == 0: 144 | self.img_size = random.choice(range(self.min_size, self.max_size + 1, 32)) 145 | # Resize images to input shape 146 | imgs = torch.stack([resize(img, self.img_size) for img in imgs]) 147 | self.batch_count += 1 148 | return paths, imgs, targets 149 | 150 | def __len__(self): 151 | return len(self.img_files) 152 | -------------------------------------------------------------------------------- /detect.py: -------------------------------------------------------------------------------- 1 | from __future__ import division 2 | 3 | from models import * 4 | from utils.utils import * 5 | from utils.datasets import * 6 | 7 | import os 8 | import sys 9 | import time 10 | import datetime 11 | import argparse 12 | 13 | from PIL import Image 14 | 15 | import torch 16 | from torch.utils.data import DataLoader 17 | from torchvision import datasets 18 | from torch.autograd import Variable 19 | 20 | import matplotlib.pyplot as plt 21 | import matplotlib.patches as patches 22 | from matplotlib.ticker import NullLocator 23 | 24 | if __name__ == "__main__": 25 | parser = argparse.ArgumentParser() 26 | parser.add_argument("--image_folder", type=str, default="data/samples", help="path to dataset") 27 | parser.add_argument("--model_def", type=str, default="config/yolov3.cfg", help="path to model definition file") 28 | parser.add_argument("--weights_path", type=str, default="weights/yolov3.weights", help="path to weights file") 29 | parser.add_argument("--class_path", type=str, default="data/coco.names", help="path to class label file") 30 | parser.add_argument("--conf_thres", type=float, default=0.8, help="object confidence threshold") 31 | parser.add_argument("--nms_thres", type=float, default=0.4, help="iou thresshold for non-maximum suppression") 32 | parser.add_argument("--batch_size", type=int, default=1, help="size of the batches") 33 | parser.add_argument("--n_cpu", type=int, default=0, help="number of cpu threads to use during batch generation") 34 | parser.add_argument("--img_size", type=int, default=416, help="size of each image dimension") 35 | parser.add_argument("--checkpoint_model", type=str, help="path to checkpoint model") 36 | opt = parser.parse_args() 37 | print(opt) 38 | 39 | device = torch.device("cuda" if torch.cuda.is_available() else "cpu") 40 | 41 | os.makedirs("output", exist_ok=True) 42 | 43 | # Set up model 44 | model = Darknet(opt.model_def, img_size=opt.img_size).to(device) 45 | 46 | if opt.weights_path.endswith(".weights"): 47 | # Load darknet weights 48 | model.load_darknet_weights(opt.weights_path) 49 | else: 50 | # Load checkpoint weights 51 | model.load_state_dict(torch.load(opt.weights_path)) 52 | 53 | model.eval() # Set in evaluation mode 54 | 55 | dataloader = DataLoader( 56 | ImageFolder(opt.image_folder, img_size=opt.img_size), 57 | batch_size=opt.batch_size, 58 | shuffle=False, 59 | num_workers=opt.n_cpu, 60 | ) 61 | 62 | classes = load_classes(opt.class_path) # Extracts class labels from file 63 | 64 | Tensor = torch.cuda.FloatTensor if torch.cuda.is_available() else torch.FloatTensor 65 | 66 | imgs = [] # Stores image paths 67 | img_detections = [] # Stores detections for each image index 68 | 69 | print("\nPerforming object detection:") 70 | prev_time = time.time() 71 | for batch_i, (img_paths, input_imgs) in enumerate(dataloader): 72 | # Configure input 73 | input_imgs = Variable(input_imgs.type(Tensor)) 74 | 75 | # Get detections 76 | with torch.no_grad(): 77 | detections = model(input_imgs) 78 | detections = non_max_suppression(detections, opt.conf_thres, opt.nms_thres) 79 | 80 | # Log progress 81 | current_time = time.time() 82 | inference_time = datetime.timedelta(seconds=current_time - prev_time) 83 | prev_time = current_time 84 | print("\t+ Batch %d, Inference Time: %s" % (batch_i, inference_time)) 85 | 86 | # Save image and detections 87 | imgs.extend(img_paths) 88 | img_detections.extend(detections) 89 | 90 | # Bounding-box colors 91 | cmap = plt.get_cmap("tab20b") 92 | colors = [cmap(i) for i in np.linspace(0, 1, 20)] 93 | 94 | print("\nSaving images:") 95 | # Iterate through images and save plot of detections 96 | for img_i, (path, detections) in enumerate(zip(imgs, img_detections)): 97 | 98 | print("(%d) Image: '%s'" % (img_i, path)) 99 | 100 | # Create plot 101 | img = np.array(Image.open(path)) 102 | plt.figure() 103 | fig, ax = plt.subplots(1) 104 | ax.imshow(img) 105 | 106 | # Draw bounding boxes and labels of detections 107 | if detections is not None: 108 | # Rescale boxes to original image 109 | detections = rescale_boxes(detections, opt.img_size, img.shape[:2]) 110 | unique_labels = detections[:, -1].cpu().unique() 111 | n_cls_preds = len(unique_labels) 112 | bbox_colors = random.sample(colors, n_cls_preds) 113 | for x1, y1, x2, y2, conf, cls_conf, cls_pred in detections: 114 | 115 | print("\t+ Label: %s, Conf: %.5f" % (classes[int(cls_pred)], cls_conf.item())) 116 | 117 | box_w = x2 - x1 118 | box_h = y2 - y1 119 | 120 | color = bbox_colors[int(np.where(unique_labels == int(cls_pred))[0])] 121 | # Create a Rectangle patch 122 | bbox = patches.Rectangle((x1, y1), box_w, box_h, linewidth=2, edgecolor=color, facecolor="none") 123 | # Add the bbox to the plot 124 | ax.add_patch(bbox) 125 | # Add label 126 | plt.text( 127 | x1, 128 | y1, 129 | s=classes[int(cls_pred)], 130 | color="white", 131 | verticalalignment="top", 132 | bbox={"color": color, "pad": 0}, 133 | ) 134 | 135 | # Save generated image with detections 136 | plt.axis("off") 137 | plt.gca().xaxis.set_major_locator(NullLocator()) 138 | plt.gca().yaxis.set_major_locator(NullLocator()) 139 | filename = path.split("/")[-1].split(".")[0] 140 | plt.savefig(f"output/{filename}.png", bbox_inches="tight", pad_inches=0.0) 141 | plt.close() 142 | -------------------------------------------------------------------------------- /train.py: -------------------------------------------------------------------------------- 1 | from __future__ import division 2 | 3 | from models import * 4 | from utils.logger import * 5 | from utils.utils import * 6 | from utils.datasets import * 7 | from utils.parse_config import * 8 | from test import evaluate 9 | 10 | from terminaltables import AsciiTable 11 | 12 | import os 13 | import sys 14 | import time 15 | import datetime 16 | import argparse 17 | 18 | import torch 19 | from torch.utils.data import DataLoader 20 | from torchvision import datasets 21 | from torchvision import transforms 22 | from torch.autograd import Variable 23 | import torch.optim as optim 24 | 25 | if __name__ == "__main__": 26 | parser = argparse.ArgumentParser() 27 | parser.add_argument("--epochs", type=int, default=10, help="number of epochs") 28 | parser.add_argument("--batch_size", type=int, default=8, help="size of each image batch") 29 | parser.add_argument("--gradient_accumulations", type=int, default=2, help="number of gradient accums before step") 30 | parser.add_argument("--model_def", type=str, default="config/yolov3-tiny.cfg", help="path to model definition file") 31 | parser.add_argument("--data_config", type=str, default="config/custom.data", help="path to data config file") 32 | parser.add_argument("--pretrained_weights", type=str, help="if specified starts from checkpoint model") 33 | parser.add_argument("--n_cpu", type=int, default=8, help="number of cpu threads to use during batch generation") 34 | parser.add_argument("--img_size", type=int, default=416, help="size of each image dimension") 35 | parser.add_argument("--checkpoint_interval", type=int, default=1, help="interval between saving model weights") 36 | parser.add_argument("--evaluation_interval", type=int, default=1, help="interval evaluations on validation set") 37 | parser.add_argument("--compute_map", default=False, help="if True computes mAP every tenth batch") 38 | parser.add_argument("--multiscale_training", default=True, help="allow for multi-scale training") 39 | opt = parser.parse_args() 40 | print(opt) 41 | 42 | logger = Logger("logs") 43 | 44 | device = torch.device("cuda" if torch.cuda.is_available() else "cpu") 45 | 46 | os.makedirs("output", exist_ok=True) 47 | os.makedirs("checkpoints", exist_ok=True) 48 | 49 | # Get data configuration 50 | data_config = parse_data_config(opt.data_config) 51 | train_path = data_config["train"] 52 | valid_path = data_config["valid"] 53 | class_names = load_classes(data_config["names"]) 54 | 55 | # Initiate model 56 | model = Darknet(opt.model_def).to(device) 57 | model.apply(weights_init_normal) 58 | 59 | # If specified we start from checkpoint 60 | if opt.pretrained_weights: 61 | if opt.pretrained_weights.endswith(".pth"): 62 | model.load_state_dict(torch.load(opt.pretrained_weights)) 63 | else: 64 | model.load_darknet_weights(opt.pretrained_weights) 65 | 66 | # Get dataloader 67 | dataset = ListDataset(train_path, augment=True, multiscale=opt.multiscale_training) 68 | dataloader = torch.utils.data.DataLoader( 69 | dataset, 70 | batch_size=opt.batch_size, 71 | shuffle=True, 72 | num_workers=opt.n_cpu, 73 | pin_memory=True, 74 | collate_fn=dataset.collate_fn, 75 | ) 76 | 77 | optimizer = torch.optim.Adam(model.parameters()) 78 | 79 | metrics = [ 80 | "grid_size", 81 | "loss", 82 | "x", 83 | "y", 84 | "w", 85 | "h", 86 | "conf", 87 | "cls", 88 | "cls_acc", 89 | "recall50", 90 | "recall75", 91 | "precision", 92 | "conf_obj", 93 | "conf_noobj", 94 | ] 95 | 96 | for epoch in range(opt.epochs): 97 | model.train() 98 | start_time = time.time() 99 | for batch_i, (_, imgs, targets) in enumerate(dataloader): 100 | batches_done = len(dataloader) * epoch + batch_i 101 | 102 | imgs = Variable(imgs.to(device)) 103 | targets = Variable(targets.to(device), requires_grad=False) 104 | 105 | loss, outputs = model(imgs, targets) 106 | loss.backward() 107 | 108 | if batches_done % opt.gradient_accumulations: 109 | # Accumulates gradient before each step 110 | optimizer.step() 111 | optimizer.zero_grad() 112 | 113 | # ---------------- 114 | # Log progress 115 | # ---------------- 116 | 117 | log_str = "\n---- [Epoch %d/%d, Batch %d/%d] ----\n" % (epoch, opt.epochs, batch_i, len(dataloader)) 118 | 119 | metric_table = [["Metrics", *[f"YOLO Layer {i}" for i in range(len(model.yolo_layers))]]] 120 | 121 | # Log metrics at each YOLO layer 122 | for i, metric in enumerate(metrics): 123 | formats = {m: "%.6f" for m in metrics} 124 | formats["grid_size"] = "%2d" 125 | formats["cls_acc"] = "%.2f%%" 126 | row_metrics = [formats[metric] % yolo.metrics.get(metric, 0) for yolo in model.yolo_layers] 127 | metric_table += [[metric, *row_metrics]] 128 | 129 | # Tensorboard logging 130 | tensorboard_log = [] 131 | for j, yolo in enumerate(model.yolo_layers): 132 | for name, metric in yolo.metrics.items(): 133 | if name != "grid_size": 134 | tensorboard_log += [(f"{name}_{j+1}", metric)] 135 | tensorboard_log += [("loss", loss.item())] 136 | logger.list_of_scalars_summary(tensorboard_log, batches_done) 137 | 138 | log_str += AsciiTable(metric_table).table 139 | log_str += f"\nTotal loss {loss.item()}" 140 | 141 | # Determine approximate time left for epoch 142 | epoch_batches_left = len(dataloader) - (batch_i + 1) 143 | time_left = datetime.timedelta(seconds=epoch_batches_left * (time.time() - start_time) / (batch_i + 1)) 144 | log_str += f"\n---- ETA {time_left}" 145 | 146 | print(log_str) 147 | 148 | model.seen += imgs.size(0) 149 | 150 | if epoch % opt.evaluation_interval == 0: 151 | print("\n---- Evaluating Model ----") 152 | # Evaluate the model on the validation set 153 | precision, recall, AP, f1, ap_class = evaluate( 154 | model, 155 | path=valid_path, 156 | iou_thres=0.5, 157 | conf_thres=0.5, 158 | nms_thres=0.5, 159 | img_size=opt.img_size, 160 | batch_size=8, 161 | ) 162 | evaluation_metrics = [ 163 | ("val_precision", precision.mean()), 164 | ("val_recall", recall.mean()), 165 | ("val_mAP", AP.mean()), 166 | ("val_f1", f1.mean()), 167 | ] 168 | logger.list_of_scalars_summary(evaluation_metrics, epoch) 169 | 170 | # Print class APs and mAP 171 | ap_table = [["Index", "Class name", "AP"]] 172 | for i, c in enumerate(ap_class): 173 | ap_table += [[c, class_names[c], "%.5f" % AP[i]]] 174 | print(AsciiTable(ap_table).table) 175 | print(f"---- mAP {AP.mean()}") 176 | 177 | if epoch % opt.checkpoint_interval == 0: 178 | torch.save(model.state_dict(), f"checkpoints/yolov3_ckpt_%d.pth" % epoch) 179 | -------------------------------------------------------------------------------- /ImageSets/Main/train.txt: -------------------------------------------------------------------------------- 1 | aircraft_100 2 | aircraft_1001 3 | aircraft_1005 4 | aircraft_1006 5 | aircraft_1009 6 | aircraft_101 7 | aircraft_1010 8 | aircraft_1011 9 | aircraft_1012 10 | aircraft_1016 11 | aircraft_1017 12 | aircraft_1018 13 | aircraft_102 14 | aircraft_1021 15 | aircraft_1023 16 | aircraft_1026 17 | aircraft_1028 18 | aircraft_1031 19 | aircraft_1032 20 | aircraft_1033 21 | aircraft_1035 22 | aircraft_1039 23 | aircraft_104 24 | aircraft_1041 25 | aircraft_105 26 | aircraft_1052 27 | aircraft_1056 28 | aircraft_1060 29 | aircraft_1061 30 | aircraft_1063 31 | aircraft_1064 32 | aircraft_1066 33 | aircraft_1067 34 | aircraft_1068 35 | aircraft_1069 36 | aircraft_107 37 | aircraft_1071 38 | aircraft_1076 39 | aircraft_1078 40 | aircraft_1081 41 | aircraft_1085 42 | aircraft_1087 43 | aircraft_1091 44 | aircraft_1095 45 | aircraft_1097 46 | aircraft_1098 47 | aircraft_1099 48 | aircraft_110 49 | aircraft_1102 50 | aircraft_1104 51 | aircraft_1105 52 | aircraft_1108 53 | aircraft_1111 54 | aircraft_1113 55 | aircraft_1114 56 | aircraft_1115 57 | aircraft_1118 58 | aircraft_1121 59 | aircraft_1124 60 | aircraft_1130 61 | aircraft_1132 62 | aircraft_1134 63 | aircraft_1137 64 | aircraft_114 65 | aircraft_116 66 | aircraft_119 67 | aircraft_120 68 | aircraft_123 69 | aircraft_127 70 | aircraft_128 71 | aircraft_129 72 | aircraft_139 73 | aircraft_14 74 | aircraft_142 75 | aircraft_145 76 | aircraft_146 77 | aircraft_149 78 | aircraft_151 79 | aircraft_152 80 | aircraft_155 81 | aircraft_158 82 | aircraft_162 83 | aircraft_164 84 | aircraft_168 85 | aircraft_175 86 | aircraft_181 87 | aircraft_185 88 | aircraft_19 89 | aircraft_190 90 | aircraft_192 91 | aircraft_194 92 | aircraft_195 93 | aircraft_198 94 | aircraft_199 95 | aircraft_202 96 | aircraft_205 97 | aircraft_21 98 | aircraft_213 99 | aircraft_215 100 | aircraft_216 101 | aircraft_218 102 | aircraft_219 103 | aircraft_22 104 | aircraft_220 105 | aircraft_223 106 | aircraft_225 107 | aircraft_227 108 | aircraft_229 109 | aircraft_23 110 | aircraft_233 111 | aircraft_239 112 | aircraft_242 113 | aircraft_244 114 | aircraft_247 115 | aircraft_260 116 | aircraft_269 117 | aircraft_27 118 | aircraft_271 119 | aircraft_275 120 | aircraft_276 121 | aircraft_277 122 | aircraft_278 123 | aircraft_283 124 | aircraft_284 125 | aircraft_287 126 | aircraft_289 127 | aircraft_290 128 | aircraft_291 129 | aircraft_293 130 | aircraft_295 131 | aircraft_30 132 | aircraft_300 133 | aircraft_302 134 | aircraft_308 135 | aircraft_313 136 | aircraft_315 137 | aircraft_319 138 | aircraft_32 139 | aircraft_322 140 | aircraft_323 141 | aircraft_33 142 | aircraft_332 143 | aircraft_34 144 | aircraft_343 145 | aircraft_344 146 | aircraft_345 147 | aircraft_346 148 | aircraft_347 149 | aircraft_348 150 | aircraft_349 151 | aircraft_351 152 | aircraft_362 153 | aircraft_364 154 | aircraft_366 155 | aircraft_373 156 | aircraft_381 157 | aircraft_383 158 | aircraft_385 159 | aircraft_395 160 | aircraft_396 161 | aircraft_4 162 | aircraft_400 163 | aircraft_401 164 | aircraft_404 165 | aircraft_405 166 | aircraft_406 167 | aircraft_410 168 | aircraft_411 169 | aircraft_415 170 | aircraft_423 171 | aircraft_428 172 | aircraft_431 173 | aircraft_432 174 | aircraft_433 175 | aircraft_435 176 | aircraft_436 177 | aircraft_438 178 | aircraft_439 179 | aircraft_444 180 | aircraft_445 181 | aircraft_447 182 | aircraft_450 183 | aircraft_452 184 | aircraft_461 185 | aircraft_464 186 | aircraft_467 187 | aircraft_471 188 | aircraft_472 189 | aircraft_474 190 | aircraft_477 191 | aircraft_479 192 | aircraft_480 193 | aircraft_485 194 | aircraft_486 195 | aircraft_487 196 | aircraft_489 197 | aircraft_49 198 | aircraft_490 199 | aircraft_491 200 | aircraft_496 201 | aircraft_497 202 | aircraft_504 203 | aircraft_506 204 | aircraft_507 205 | aircraft_508 206 | aircraft_509 207 | aircraft_510 208 | aircraft_516 209 | aircraft_520 210 | aircraft_521 211 | aircraft_523 212 | aircraft_524 213 | aircraft_525 214 | aircraft_526 215 | aircraft_527 216 | aircraft_536 217 | aircraft_538 218 | aircraft_539 219 | aircraft_543 220 | aircraft_544 221 | aircraft_550 222 | aircraft_559 223 | aircraft_569 224 | aircraft_57 225 | aircraft_572 226 | aircraft_575 227 | aircraft_579 228 | aircraft_580 229 | aircraft_581 230 | aircraft_582 231 | aircraft_583 232 | aircraft_589 233 | aircraft_59 234 | aircraft_591 235 | aircraft_593 236 | aircraft_601 237 | aircraft_608 238 | aircraft_609 239 | aircraft_613 240 | aircraft_615 241 | aircraft_617 242 | aircraft_619 243 | aircraft_622 244 | aircraft_623 245 | aircraft_626 246 | aircraft_627 247 | aircraft_628 248 | aircraft_632 249 | aircraft_637 250 | aircraft_640 251 | aircraft_643 252 | aircraft_644 253 | aircraft_645 254 | aircraft_646 255 | aircraft_648 256 | aircraft_651 257 | aircraft_654 258 | aircraft_656 259 | aircraft_661 260 | aircraft_662 261 | aircraft_666 262 | aircraft_667 263 | aircraft_676 264 | aircraft_677 265 | aircraft_678 266 | aircraft_680 267 | aircraft_682 268 | aircraft_683 269 | aircraft_684 270 | aircraft_685 271 | aircraft_688 272 | aircraft_689 273 | aircraft_69 274 | aircraft_693 275 | aircraft_698 276 | aircraft_70 277 | aircraft_700 278 | aircraft_701 279 | aircraft_703 280 | aircraft_706 281 | aircraft_712 282 | aircraft_716 283 | aircraft_719 284 | aircraft_720 285 | aircraft_721 286 | aircraft_723 287 | aircraft_726 288 | aircraft_727 289 | aircraft_728 290 | aircraft_729 291 | aircraft_731 292 | aircraft_735 293 | aircraft_738 294 | aircraft_739 295 | aircraft_740 296 | aircraft_741 297 | aircraft_742 298 | aircraft_743 299 | aircraft_744 300 | aircraft_758 301 | aircraft_77 302 | aircraft_770 303 | aircraft_772 304 | aircraft_773 305 | aircraft_780 306 | aircraft_781 307 | aircraft_783 308 | aircraft_786 309 | aircraft_787 310 | aircraft_789 311 | aircraft_79 312 | aircraft_791 313 | aircraft_796 314 | aircraft_798 315 | aircraft_799 316 | aircraft_8 317 | aircraft_80 318 | aircraft_801 319 | aircraft_802 320 | aircraft_803 321 | aircraft_804 322 | aircraft_805 323 | aircraft_807 324 | aircraft_809 325 | aircraft_810 326 | aircraft_814 327 | aircraft_818 328 | aircraft_82 329 | aircraft_820 330 | aircraft_822 331 | aircraft_824 332 | aircraft_825 333 | aircraft_826 334 | aircraft_827 335 | aircraft_828 336 | aircraft_831 337 | aircraft_832 338 | aircraft_836 339 | aircraft_844 340 | aircraft_848 341 | aircraft_851 342 | aircraft_856 343 | aircraft_858 344 | aircraft_861 345 | aircraft_862 346 | aircraft_863 347 | aircraft_864 348 | aircraft_867 349 | aircraft_868 350 | aircraft_87 351 | aircraft_874 352 | aircraft_878 353 | aircraft_88 354 | aircraft_881 355 | aircraft_883 356 | aircraft_884 357 | aircraft_885 358 | aircraft_887 359 | aircraft_894 360 | aircraft_897 361 | aircraft_90 362 | aircraft_900 363 | aircraft_902 364 | aircraft_903 365 | aircraft_904 366 | aircraft_905 367 | aircraft_907 368 | aircraft_908 369 | aircraft_912 370 | aircraft_914 371 | aircraft_916 372 | aircraft_921 373 | aircraft_923 374 | aircraft_924 375 | aircraft_925 376 | aircraft_933 377 | aircraft_939 378 | aircraft_940 379 | aircraft_943 380 | aircraft_948 381 | aircraft_949 382 | aircraft_950 383 | aircraft_953 384 | aircraft_957 385 | aircraft_962 386 | aircraft_963 387 | aircraft_964 388 | aircraft_965 389 | aircraft_966 390 | aircraft_969 391 | aircraft_973 392 | aircraft_977 393 | aircraft_978 394 | aircraft_979 395 | aircraft_98 396 | aircraft_985 397 | aircraft_986 398 | aircraft_99 399 | aircraft_993 400 | aircraft_996 401 | aircraft_997 402 | aircraft_998 403 | -------------------------------------------------------------------------------- /data/ImageSets/Main/train.txt: -------------------------------------------------------------------------------- 1 | aircraft_100 2 | aircraft_1001 3 | aircraft_1005 4 | aircraft_1006 5 | aircraft_1009 6 | aircraft_101 7 | aircraft_1010 8 | aircraft_1011 9 | aircraft_1012 10 | aircraft_1016 11 | aircraft_1017 12 | aircraft_1018 13 | aircraft_102 14 | aircraft_1021 15 | aircraft_1023 16 | aircraft_1026 17 | aircraft_1028 18 | aircraft_1031 19 | aircraft_1032 20 | aircraft_1033 21 | aircraft_1035 22 | aircraft_1039 23 | aircraft_104 24 | aircraft_1041 25 | aircraft_105 26 | aircraft_1052 27 | aircraft_1056 28 | aircraft_1060 29 | aircraft_1061 30 | aircraft_1063 31 | aircraft_1064 32 | aircraft_1066 33 | aircraft_1067 34 | aircraft_1068 35 | aircraft_1069 36 | aircraft_107 37 | aircraft_1071 38 | aircraft_1076 39 | aircraft_1078 40 | aircraft_1081 41 | aircraft_1085 42 | aircraft_1087 43 | aircraft_1091 44 | aircraft_1095 45 | aircraft_1097 46 | aircraft_1098 47 | aircraft_1099 48 | aircraft_110 49 | aircraft_1102 50 | aircraft_1104 51 | aircraft_1105 52 | aircraft_1108 53 | aircraft_1111 54 | aircraft_1113 55 | aircraft_1114 56 | aircraft_1115 57 | aircraft_1118 58 | aircraft_1121 59 | aircraft_1124 60 | aircraft_1130 61 | aircraft_1132 62 | aircraft_1134 63 | aircraft_1137 64 | aircraft_114 65 | aircraft_116 66 | aircraft_119 67 | aircraft_120 68 | aircraft_123 69 | aircraft_127 70 | aircraft_128 71 | aircraft_129 72 | aircraft_139 73 | aircraft_14 74 | aircraft_142 75 | aircraft_145 76 | aircraft_146 77 | aircraft_149 78 | aircraft_151 79 | aircraft_152 80 | aircraft_155 81 | aircraft_158 82 | aircraft_162 83 | aircraft_164 84 | aircraft_168 85 | aircraft_175 86 | aircraft_181 87 | aircraft_185 88 | aircraft_19 89 | aircraft_190 90 | aircraft_192 91 | aircraft_194 92 | aircraft_195 93 | aircraft_198 94 | aircraft_199 95 | aircraft_202 96 | aircraft_205 97 | aircraft_21 98 | aircraft_213 99 | aircraft_215 100 | aircraft_216 101 | aircraft_218 102 | aircraft_219 103 | aircraft_22 104 | aircraft_220 105 | aircraft_223 106 | aircraft_225 107 | aircraft_227 108 | aircraft_229 109 | aircraft_23 110 | aircraft_233 111 | aircraft_239 112 | aircraft_242 113 | aircraft_244 114 | aircraft_247 115 | aircraft_260 116 | aircraft_269 117 | aircraft_27 118 | aircraft_271 119 | aircraft_275 120 | aircraft_276 121 | aircraft_277 122 | aircraft_278 123 | aircraft_283 124 | aircraft_284 125 | aircraft_287 126 | aircraft_289 127 | aircraft_290 128 | aircraft_291 129 | aircraft_293 130 | aircraft_295 131 | aircraft_30 132 | aircraft_300 133 | aircraft_302 134 | aircraft_308 135 | aircraft_313 136 | aircraft_315 137 | aircraft_319 138 | aircraft_32 139 | aircraft_322 140 | aircraft_323 141 | aircraft_33 142 | aircraft_332 143 | aircraft_34 144 | aircraft_343 145 | aircraft_344 146 | aircraft_345 147 | aircraft_346 148 | aircraft_347 149 | aircraft_348 150 | aircraft_349 151 | aircraft_351 152 | aircraft_362 153 | aircraft_364 154 | aircraft_366 155 | aircraft_373 156 | aircraft_381 157 | aircraft_383 158 | aircraft_385 159 | aircraft_395 160 | aircraft_396 161 | aircraft_4 162 | aircraft_400 163 | aircraft_401 164 | aircraft_404 165 | aircraft_405 166 | aircraft_406 167 | aircraft_410 168 | aircraft_411 169 | aircraft_415 170 | aircraft_423 171 | aircraft_428 172 | aircraft_431 173 | aircraft_432 174 | aircraft_433 175 | aircraft_435 176 | aircraft_436 177 | aircraft_438 178 | aircraft_439 179 | aircraft_444 180 | aircraft_445 181 | aircraft_447 182 | aircraft_450 183 | aircraft_452 184 | aircraft_461 185 | aircraft_464 186 | aircraft_467 187 | aircraft_471 188 | aircraft_472 189 | aircraft_474 190 | aircraft_477 191 | aircraft_479 192 | aircraft_480 193 | aircraft_485 194 | aircraft_486 195 | aircraft_487 196 | aircraft_489 197 | aircraft_49 198 | aircraft_490 199 | aircraft_491 200 | aircraft_496 201 | aircraft_497 202 | aircraft_504 203 | aircraft_506 204 | aircraft_507 205 | aircraft_508 206 | aircraft_509 207 | aircraft_510 208 | aircraft_516 209 | aircraft_520 210 | aircraft_521 211 | aircraft_523 212 | aircraft_524 213 | aircraft_525 214 | aircraft_526 215 | aircraft_527 216 | aircraft_536 217 | aircraft_538 218 | aircraft_539 219 | aircraft_543 220 | aircraft_544 221 | aircraft_550 222 | aircraft_559 223 | aircraft_569 224 | aircraft_57 225 | aircraft_572 226 | aircraft_575 227 | aircraft_579 228 | aircraft_580 229 | aircraft_581 230 | aircraft_582 231 | aircraft_583 232 | aircraft_589 233 | aircraft_59 234 | aircraft_591 235 | aircraft_593 236 | aircraft_601 237 | aircraft_608 238 | aircraft_609 239 | aircraft_613 240 | aircraft_615 241 | aircraft_617 242 | aircraft_619 243 | aircraft_622 244 | aircraft_623 245 | aircraft_626 246 | aircraft_627 247 | aircraft_628 248 | aircraft_632 249 | aircraft_637 250 | aircraft_640 251 | aircraft_643 252 | aircraft_644 253 | aircraft_645 254 | aircraft_646 255 | aircraft_648 256 | aircraft_651 257 | aircraft_654 258 | aircraft_656 259 | aircraft_661 260 | aircraft_662 261 | aircraft_666 262 | aircraft_667 263 | aircraft_676 264 | aircraft_677 265 | aircraft_678 266 | aircraft_680 267 | aircraft_682 268 | aircraft_683 269 | aircraft_684 270 | aircraft_685 271 | aircraft_688 272 | aircraft_689 273 | aircraft_69 274 | aircraft_693 275 | aircraft_698 276 | aircraft_70 277 | aircraft_700 278 | aircraft_701 279 | aircraft_703 280 | aircraft_706 281 | aircraft_712 282 | aircraft_716 283 | aircraft_719 284 | aircraft_720 285 | aircraft_721 286 | aircraft_723 287 | aircraft_726 288 | aircraft_727 289 | aircraft_728 290 | aircraft_729 291 | aircraft_731 292 | aircraft_735 293 | aircraft_738 294 | aircraft_739 295 | aircraft_740 296 | aircraft_741 297 | aircraft_742 298 | aircraft_743 299 | aircraft_744 300 | aircraft_758 301 | aircraft_77 302 | aircraft_770 303 | aircraft_772 304 | aircraft_773 305 | aircraft_780 306 | aircraft_781 307 | aircraft_783 308 | aircraft_786 309 | aircraft_787 310 | aircraft_789 311 | aircraft_79 312 | aircraft_791 313 | aircraft_796 314 | aircraft_798 315 | aircraft_799 316 | aircraft_8 317 | aircraft_80 318 | aircraft_801 319 | aircraft_802 320 | aircraft_803 321 | aircraft_804 322 | aircraft_805 323 | aircraft_807 324 | aircraft_809 325 | aircraft_810 326 | aircraft_814 327 | aircraft_818 328 | aircraft_82 329 | aircraft_820 330 | aircraft_822 331 | aircraft_824 332 | aircraft_825 333 | aircraft_826 334 | aircraft_827 335 | aircraft_828 336 | aircraft_831 337 | aircraft_832 338 | aircraft_836 339 | aircraft_844 340 | aircraft_848 341 | aircraft_851 342 | aircraft_856 343 | aircraft_858 344 | aircraft_861 345 | aircraft_862 346 | aircraft_863 347 | aircraft_864 348 | aircraft_867 349 | aircraft_868 350 | aircraft_87 351 | aircraft_874 352 | aircraft_878 353 | aircraft_88 354 | aircraft_881 355 | aircraft_883 356 | aircraft_884 357 | aircraft_885 358 | aircraft_887 359 | aircraft_894 360 | aircraft_897 361 | aircraft_90 362 | aircraft_900 363 | aircraft_902 364 | aircraft_903 365 | aircraft_904 366 | aircraft_905 367 | aircraft_907 368 | aircraft_908 369 | aircraft_912 370 | aircraft_914 371 | aircraft_916 372 | aircraft_921 373 | aircraft_923 374 | aircraft_924 375 | aircraft_925 376 | aircraft_933 377 | aircraft_939 378 | aircraft_940 379 | aircraft_943 380 | aircraft_948 381 | aircraft_949 382 | aircraft_950 383 | aircraft_953 384 | aircraft_957 385 | aircraft_962 386 | aircraft_963 387 | aircraft_964 388 | aircraft_965 389 | aircraft_966 390 | aircraft_969 391 | aircraft_973 392 | aircraft_977 393 | aircraft_978 394 | aircraft_979 395 | aircraft_98 396 | aircraft_985 397 | aircraft_986 398 | aircraft_99 399 | aircraft_993 400 | aircraft_996 401 | aircraft_997 402 | aircraft_998 403 | -------------------------------------------------------------------------------- /config/yolov3.cfg: -------------------------------------------------------------------------------- 1 | [net] 2 | # Testing 3 | #batch=1 4 | #subdivisions=1 5 | # Training 6 | batch=16 7 | subdivisions=1 8 | width=416 9 | height=416 10 | channels=3 11 | momentum=0.9 12 | decay=0.0005 13 | angle=0 14 | saturation = 1.5 15 | exposure = 1.5 16 | hue=.1 17 | 18 | learning_rate=0.001 19 | burn_in=1000 20 | max_batches = 500200 21 | policy=steps 22 | steps=400000,450000 23 | scales=.1,.1 24 | 25 | [convolutional] 26 | batch_normalize=1 27 | filters=32 28 | size=3 29 | stride=1 30 | pad=1 31 | activation=leaky 32 | 33 | # Downsample 34 | 35 | [convolutional] 36 | batch_normalize=1 37 | filters=64 38 | size=3 39 | stride=2 40 | pad=1 41 | activation=leaky 42 | 43 | [convolutional] 44 | batch_normalize=1 45 | filters=32 46 | size=1 47 | stride=1 48 | pad=1 49 | activation=leaky 50 | 51 | [convolutional] 52 | batch_normalize=1 53 | filters=64 54 | size=3 55 | stride=1 56 | pad=1 57 | activation=leaky 58 | 59 | [shortcut] 60 | from=-3 61 | activation=linear 62 | 63 | # Downsample 64 | 65 | [convolutional] 66 | batch_normalize=1 67 | filters=128 68 | size=3 69 | stride=2 70 | pad=1 71 | activation=leaky 72 | 73 | [convolutional] 74 | batch_normalize=1 75 | filters=64 76 | size=1 77 | stride=1 78 | pad=1 79 | activation=leaky 80 | 81 | [convolutional] 82 | batch_normalize=1 83 | filters=128 84 | size=3 85 | stride=1 86 | pad=1 87 | activation=leaky 88 | 89 | [shortcut] 90 | from=-3 91 | activation=linear 92 | 93 | [convolutional] 94 | batch_normalize=1 95 | filters=64 96 | size=1 97 | stride=1 98 | pad=1 99 | activation=leaky 100 | 101 | [convolutional] 102 | batch_normalize=1 103 | filters=128 104 | size=3 105 | stride=1 106 | pad=1 107 | activation=leaky 108 | 109 | [shortcut] 110 | from=-3 111 | activation=linear 112 | 113 | # Downsample 114 | 115 | [convolutional] 116 | batch_normalize=1 117 | filters=256 118 | size=3 119 | stride=2 120 | pad=1 121 | activation=leaky 122 | 123 | [convolutional] 124 | batch_normalize=1 125 | filters=128 126 | size=1 127 | stride=1 128 | pad=1 129 | activation=leaky 130 | 131 | [convolutional] 132 | batch_normalize=1 133 | filters=256 134 | size=3 135 | stride=1 136 | pad=1 137 | activation=leaky 138 | 139 | [shortcut] 140 | from=-3 141 | activation=linear 142 | 143 | [convolutional] 144 | batch_normalize=1 145 | filters=128 146 | size=1 147 | stride=1 148 | pad=1 149 | activation=leaky 150 | 151 | [convolutional] 152 | batch_normalize=1 153 | filters=256 154 | size=3 155 | stride=1 156 | pad=1 157 | activation=leaky 158 | 159 | [shortcut] 160 | from=-3 161 | activation=linear 162 | 163 | [convolutional] 164 | batch_normalize=1 165 | filters=128 166 | size=1 167 | stride=1 168 | pad=1 169 | activation=leaky 170 | 171 | [convolutional] 172 | batch_normalize=1 173 | filters=256 174 | size=3 175 | stride=1 176 | pad=1 177 | activation=leaky 178 | 179 | [shortcut] 180 | from=-3 181 | activation=linear 182 | 183 | [convolutional] 184 | batch_normalize=1 185 | filters=128 186 | size=1 187 | stride=1 188 | pad=1 189 | activation=leaky 190 | 191 | [convolutional] 192 | batch_normalize=1 193 | filters=256 194 | size=3 195 | stride=1 196 | pad=1 197 | activation=leaky 198 | 199 | [shortcut] 200 | from=-3 201 | activation=linear 202 | 203 | 204 | [convolutional] 205 | batch_normalize=1 206 | filters=128 207 | size=1 208 | stride=1 209 | pad=1 210 | activation=leaky 211 | 212 | [convolutional] 213 | batch_normalize=1 214 | filters=256 215 | size=3 216 | stride=1 217 | pad=1 218 | activation=leaky 219 | 220 | [shortcut] 221 | from=-3 222 | activation=linear 223 | 224 | [convolutional] 225 | batch_normalize=1 226 | filters=128 227 | size=1 228 | stride=1 229 | pad=1 230 | activation=leaky 231 | 232 | [convolutional] 233 | batch_normalize=1 234 | filters=256 235 | size=3 236 | stride=1 237 | pad=1 238 | activation=leaky 239 | 240 | [shortcut] 241 | from=-3 242 | activation=linear 243 | 244 | [convolutional] 245 | batch_normalize=1 246 | filters=128 247 | size=1 248 | stride=1 249 | pad=1 250 | activation=leaky 251 | 252 | [convolutional] 253 | batch_normalize=1 254 | filters=256 255 | size=3 256 | stride=1 257 | pad=1 258 | activation=leaky 259 | 260 | [shortcut] 261 | from=-3 262 | activation=linear 263 | 264 | [convolutional] 265 | batch_normalize=1 266 | filters=128 267 | size=1 268 | stride=1 269 | pad=1 270 | activation=leaky 271 | 272 | [convolutional] 273 | batch_normalize=1 274 | filters=256 275 | size=3 276 | stride=1 277 | pad=1 278 | activation=leaky 279 | 280 | [shortcut] 281 | from=-3 282 | activation=linear 283 | 284 | # Downsample 285 | 286 | [convolutional] 287 | batch_normalize=1 288 | filters=512 289 | size=3 290 | stride=2 291 | pad=1 292 | activation=leaky 293 | 294 | [convolutional] 295 | batch_normalize=1 296 | filters=256 297 | size=1 298 | stride=1 299 | pad=1 300 | activation=leaky 301 | 302 | [convolutional] 303 | batch_normalize=1 304 | filters=512 305 | size=3 306 | stride=1 307 | pad=1 308 | activation=leaky 309 | 310 | [shortcut] 311 | from=-3 312 | activation=linear 313 | 314 | 315 | [convolutional] 316 | batch_normalize=1 317 | filters=256 318 | size=1 319 | stride=1 320 | pad=1 321 | activation=leaky 322 | 323 | [convolutional] 324 | batch_normalize=1 325 | filters=512 326 | size=3 327 | stride=1 328 | pad=1 329 | activation=leaky 330 | 331 | [shortcut] 332 | from=-3 333 | activation=linear 334 | 335 | 336 | [convolutional] 337 | batch_normalize=1 338 | filters=256 339 | size=1 340 | stride=1 341 | pad=1 342 | activation=leaky 343 | 344 | [convolutional] 345 | batch_normalize=1 346 | filters=512 347 | size=3 348 | stride=1 349 | pad=1 350 | activation=leaky 351 | 352 | [shortcut] 353 | from=-3 354 | activation=linear 355 | 356 | 357 | [convolutional] 358 | batch_normalize=1 359 | filters=256 360 | size=1 361 | stride=1 362 | pad=1 363 | activation=leaky 364 | 365 | [convolutional] 366 | batch_normalize=1 367 | filters=512 368 | size=3 369 | stride=1 370 | pad=1 371 | activation=leaky 372 | 373 | [shortcut] 374 | from=-3 375 | activation=linear 376 | 377 | [convolutional] 378 | batch_normalize=1 379 | filters=256 380 | size=1 381 | stride=1 382 | pad=1 383 | activation=leaky 384 | 385 | [convolutional] 386 | batch_normalize=1 387 | filters=512 388 | size=3 389 | stride=1 390 | pad=1 391 | activation=leaky 392 | 393 | [shortcut] 394 | from=-3 395 | activation=linear 396 | 397 | 398 | [convolutional] 399 | batch_normalize=1 400 | filters=256 401 | size=1 402 | stride=1 403 | pad=1 404 | activation=leaky 405 | 406 | [convolutional] 407 | batch_normalize=1 408 | filters=512 409 | size=3 410 | stride=1 411 | pad=1 412 | activation=leaky 413 | 414 | [shortcut] 415 | from=-3 416 | activation=linear 417 | 418 | 419 | [convolutional] 420 | batch_normalize=1 421 | filters=256 422 | size=1 423 | stride=1 424 | pad=1 425 | activation=leaky 426 | 427 | [convolutional] 428 | batch_normalize=1 429 | filters=512 430 | size=3 431 | stride=1 432 | pad=1 433 | activation=leaky 434 | 435 | [shortcut] 436 | from=-3 437 | activation=linear 438 | 439 | [convolutional] 440 | batch_normalize=1 441 | filters=256 442 | size=1 443 | stride=1 444 | pad=1 445 | activation=leaky 446 | 447 | [convolutional] 448 | batch_normalize=1 449 | filters=512 450 | size=3 451 | stride=1 452 | pad=1 453 | activation=leaky 454 | 455 | [shortcut] 456 | from=-3 457 | activation=linear 458 | 459 | # Downsample 460 | 461 | [convolutional] 462 | batch_normalize=1 463 | filters=1024 464 | size=3 465 | stride=2 466 | pad=1 467 | activation=leaky 468 | 469 | [convolutional] 470 | batch_normalize=1 471 | filters=512 472 | size=1 473 | stride=1 474 | pad=1 475 | activation=leaky 476 | 477 | [convolutional] 478 | batch_normalize=1 479 | filters=1024 480 | size=3 481 | stride=1 482 | pad=1 483 | activation=leaky 484 | 485 | [shortcut] 486 | from=-3 487 | activation=linear 488 | 489 | [convolutional] 490 | batch_normalize=1 491 | filters=512 492 | size=1 493 | stride=1 494 | pad=1 495 | activation=leaky 496 | 497 | [convolutional] 498 | batch_normalize=1 499 | filters=1024 500 | size=3 501 | stride=1 502 | pad=1 503 | activation=leaky 504 | 505 | [shortcut] 506 | from=-3 507 | activation=linear 508 | 509 | [convolutional] 510 | batch_normalize=1 511 | filters=512 512 | size=1 513 | stride=1 514 | pad=1 515 | activation=leaky 516 | 517 | [convolutional] 518 | batch_normalize=1 519 | filters=1024 520 | size=3 521 | stride=1 522 | pad=1 523 | activation=leaky 524 | 525 | [shortcut] 526 | from=-3 527 | activation=linear 528 | 529 | [convolutional] 530 | batch_normalize=1 531 | filters=512 532 | size=1 533 | stride=1 534 | pad=1 535 | activation=leaky 536 | 537 | [convolutional] 538 | batch_normalize=1 539 | filters=1024 540 | size=3 541 | stride=1 542 | pad=1 543 | activation=leaky 544 | 545 | [shortcut] 546 | from=-3 547 | activation=linear 548 | 549 | ###################### 550 | 551 | [convolutional] 552 | batch_normalize=1 553 | filters=512 554 | size=1 555 | stride=1 556 | pad=1 557 | activation=leaky 558 | 559 | [convolutional] 560 | batch_normalize=1 561 | size=3 562 | stride=1 563 | pad=1 564 | filters=1024 565 | activation=leaky 566 | 567 | [convolutional] 568 | batch_normalize=1 569 | filters=512 570 | size=1 571 | stride=1 572 | pad=1 573 | activation=leaky 574 | 575 | [convolutional] 576 | batch_normalize=1 577 | size=3 578 | stride=1 579 | pad=1 580 | filters=1024 581 | activation=leaky 582 | 583 | [convolutional] 584 | batch_normalize=1 585 | filters=512 586 | size=1 587 | stride=1 588 | pad=1 589 | activation=leaky 590 | 591 | [convolutional] 592 | batch_normalize=1 593 | size=3 594 | stride=1 595 | pad=1 596 | filters=1024 597 | activation=leaky 598 | 599 | [convolutional] 600 | size=1 601 | stride=1 602 | pad=1 603 | filters=255 604 | activation=linear 605 | 606 | 607 | [yolo] 608 | mask = 6,7,8 609 | anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 610 | classes=80 611 | num=9 612 | jitter=.3 613 | ignore_thresh = .7 614 | truth_thresh = 1 615 | random=1 616 | 617 | 618 | [route] 619 | layers = -4 620 | 621 | [convolutional] 622 | batch_normalize=1 623 | filters=256 624 | size=1 625 | stride=1 626 | pad=1 627 | activation=leaky 628 | 629 | [upsample] 630 | stride=2 631 | 632 | [route] 633 | layers = -1, 61 634 | 635 | 636 | 637 | [convolutional] 638 | batch_normalize=1 639 | filters=256 640 | size=1 641 | stride=1 642 | pad=1 643 | activation=leaky 644 | 645 | [convolutional] 646 | batch_normalize=1 647 | size=3 648 | stride=1 649 | pad=1 650 | filters=512 651 | activation=leaky 652 | 653 | [convolutional] 654 | batch_normalize=1 655 | filters=256 656 | size=1 657 | stride=1 658 | pad=1 659 | activation=leaky 660 | 661 | [convolutional] 662 | batch_normalize=1 663 | size=3 664 | stride=1 665 | pad=1 666 | filters=512 667 | activation=leaky 668 | 669 | [convolutional] 670 | batch_normalize=1 671 | filters=256 672 | size=1 673 | stride=1 674 | pad=1 675 | activation=leaky 676 | 677 | [convolutional] 678 | batch_normalize=1 679 | size=3 680 | stride=1 681 | pad=1 682 | filters=512 683 | activation=leaky 684 | 685 | [convolutional] 686 | size=1 687 | stride=1 688 | pad=1 689 | filters=255 690 | activation=linear 691 | 692 | 693 | [yolo] 694 | mask = 3,4,5 695 | anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 696 | classes=80 697 | num=9 698 | jitter=.3 699 | ignore_thresh = .7 700 | truth_thresh = 1 701 | random=1 702 | 703 | 704 | 705 | [route] 706 | layers = -4 707 | 708 | [convolutional] 709 | batch_normalize=1 710 | filters=128 711 | size=1 712 | stride=1 713 | pad=1 714 | activation=leaky 715 | 716 | [upsample] 717 | stride=2 718 | 719 | [route] 720 | layers = -1, 36 721 | 722 | 723 | 724 | [convolutional] 725 | batch_normalize=1 726 | filters=128 727 | size=1 728 | stride=1 729 | pad=1 730 | activation=leaky 731 | 732 | [convolutional] 733 | batch_normalize=1 734 | size=3 735 | stride=1 736 | pad=1 737 | filters=256 738 | activation=leaky 739 | 740 | [convolutional] 741 | batch_normalize=1 742 | filters=128 743 | size=1 744 | stride=1 745 | pad=1 746 | activation=leaky 747 | 748 | [convolutional] 749 | batch_normalize=1 750 | size=3 751 | stride=1 752 | pad=1 753 | filters=256 754 | activation=leaky 755 | 756 | [convolutional] 757 | batch_normalize=1 758 | filters=128 759 | size=1 760 | stride=1 761 | pad=1 762 | activation=leaky 763 | 764 | [convolutional] 765 | batch_normalize=1 766 | size=3 767 | stride=1 768 | pad=1 769 | filters=256 770 | activation=leaky 771 | 772 | [convolutional] 773 | size=1 774 | stride=1 775 | pad=1 776 | filters=255 777 | activation=linear 778 | 779 | 780 | [yolo] 781 | mask = 0,1,2 782 | anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 783 | classes=80 784 | num=9 785 | jitter=.3 786 | ignore_thresh = .7 787 | truth_thresh = 1 788 | random=1 789 | -------------------------------------------------------------------------------- /config/create_custom_model.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | NUM_CLASSES=$1 4 | 5 | echo " 6 | [net] 7 | # Testing 8 | #batch=1 9 | #subdivisions=1 10 | # Training 11 | batch=16 12 | subdivisions=1 13 | width=416 14 | height=416 15 | channels=3 16 | momentum=0.9 17 | decay=0.0005 18 | angle=0 19 | saturation = 1.5 20 | exposure = 1.5 21 | hue=.1 22 | 23 | learning_rate=0.001 24 | burn_in=1000 25 | max_batches = 500200 26 | policy=steps 27 | steps=400000,450000 28 | scales=.1,.1 29 | 30 | [convolutional] 31 | batch_normalize=1 32 | filters=32 33 | size=3 34 | stride=1 35 | pad=1 36 | activation=leaky 37 | 38 | # Downsample 39 | 40 | [convolutional] 41 | batch_normalize=1 42 | filters=64 43 | size=3 44 | stride=2 45 | pad=1 46 | activation=leaky 47 | 48 | [convolutional] 49 | batch_normalize=1 50 | filters=32 51 | size=1 52 | stride=1 53 | pad=1 54 | activation=leaky 55 | 56 | [convolutional] 57 | batch_normalize=1 58 | filters=64 59 | size=3 60 | stride=1 61 | pad=1 62 | activation=leaky 63 | 64 | [shortcut] 65 | from=-3 66 | activation=linear 67 | 68 | # Downsample 69 | 70 | [convolutional] 71 | batch_normalize=1 72 | filters=128 73 | size=3 74 | stride=2 75 | pad=1 76 | activation=leaky 77 | 78 | [convolutional] 79 | batch_normalize=1 80 | filters=64 81 | size=1 82 | stride=1 83 | pad=1 84 | activation=leaky 85 | 86 | [convolutional] 87 | batch_normalize=1 88 | filters=128 89 | size=3 90 | stride=1 91 | pad=1 92 | activation=leaky 93 | 94 | [shortcut] 95 | from=-3 96 | activation=linear 97 | 98 | [convolutional] 99 | batch_normalize=1 100 | filters=64 101 | size=1 102 | stride=1 103 | pad=1 104 | activation=leaky 105 | 106 | [convolutional] 107 | batch_normalize=1 108 | filters=128 109 | size=3 110 | stride=1 111 | pad=1 112 | activation=leaky 113 | 114 | [shortcut] 115 | from=-3 116 | activation=linear 117 | 118 | # Downsample 119 | 120 | [convolutional] 121 | batch_normalize=1 122 | filters=256 123 | size=3 124 | stride=2 125 | pad=1 126 | activation=leaky 127 | 128 | [convolutional] 129 | batch_normalize=1 130 | filters=128 131 | size=1 132 | stride=1 133 | pad=1 134 | activation=leaky 135 | 136 | [convolutional] 137 | batch_normalize=1 138 | filters=256 139 | size=3 140 | stride=1 141 | pad=1 142 | activation=leaky 143 | 144 | [shortcut] 145 | from=-3 146 | activation=linear 147 | 148 | [convolutional] 149 | batch_normalize=1 150 | filters=128 151 | size=1 152 | stride=1 153 | pad=1 154 | activation=leaky 155 | 156 | [convolutional] 157 | batch_normalize=1 158 | filters=256 159 | size=3 160 | stride=1 161 | pad=1 162 | activation=leaky 163 | 164 | [shortcut] 165 | from=-3 166 | activation=linear 167 | 168 | [convolutional] 169 | batch_normalize=1 170 | filters=128 171 | size=1 172 | stride=1 173 | pad=1 174 | activation=leaky 175 | 176 | [convolutional] 177 | batch_normalize=1 178 | filters=256 179 | size=3 180 | stride=1 181 | pad=1 182 | activation=leaky 183 | 184 | [shortcut] 185 | from=-3 186 | activation=linear 187 | 188 | [convolutional] 189 | batch_normalize=1 190 | filters=128 191 | size=1 192 | stride=1 193 | pad=1 194 | activation=leaky 195 | 196 | [convolutional] 197 | batch_normalize=1 198 | filters=256 199 | size=3 200 | stride=1 201 | pad=1 202 | activation=leaky 203 | 204 | [shortcut] 205 | from=-3 206 | activation=linear 207 | 208 | 209 | [convolutional] 210 | batch_normalize=1 211 | filters=128 212 | size=1 213 | stride=1 214 | pad=1 215 | activation=leaky 216 | 217 | [convolutional] 218 | batch_normalize=1 219 | filters=256 220 | size=3 221 | stride=1 222 | pad=1 223 | activation=leaky 224 | 225 | [shortcut] 226 | from=-3 227 | activation=linear 228 | 229 | [convolutional] 230 | batch_normalize=1 231 | filters=128 232 | size=1 233 | stride=1 234 | pad=1 235 | activation=leaky 236 | 237 | [convolutional] 238 | batch_normalize=1 239 | filters=256 240 | size=3 241 | stride=1 242 | pad=1 243 | activation=leaky 244 | 245 | [shortcut] 246 | from=-3 247 | activation=linear 248 | 249 | [convolutional] 250 | batch_normalize=1 251 | filters=128 252 | size=1 253 | stride=1 254 | pad=1 255 | activation=leaky 256 | 257 | [convolutional] 258 | batch_normalize=1 259 | filters=256 260 | size=3 261 | stride=1 262 | pad=1 263 | activation=leaky 264 | 265 | [shortcut] 266 | from=-3 267 | activation=linear 268 | 269 | [convolutional] 270 | batch_normalize=1 271 | filters=128 272 | size=1 273 | stride=1 274 | pad=1 275 | activation=leaky 276 | 277 | [convolutional] 278 | batch_normalize=1 279 | filters=256 280 | size=3 281 | stride=1 282 | pad=1 283 | activation=leaky 284 | 285 | [shortcut] 286 | from=-3 287 | activation=linear 288 | 289 | # Downsample 290 | 291 | [convolutional] 292 | batch_normalize=1 293 | filters=512 294 | size=3 295 | stride=2 296 | pad=1 297 | activation=leaky 298 | 299 | [convolutional] 300 | batch_normalize=1 301 | filters=256 302 | size=1 303 | stride=1 304 | pad=1 305 | activation=leaky 306 | 307 | [convolutional] 308 | batch_normalize=1 309 | filters=512 310 | size=3 311 | stride=1 312 | pad=1 313 | activation=leaky 314 | 315 | [shortcut] 316 | from=-3 317 | activation=linear 318 | 319 | 320 | [convolutional] 321 | batch_normalize=1 322 | filters=256 323 | size=1 324 | stride=1 325 | pad=1 326 | activation=leaky 327 | 328 | [convolutional] 329 | batch_normalize=1 330 | filters=512 331 | size=3 332 | stride=1 333 | pad=1 334 | activation=leaky 335 | 336 | [shortcut] 337 | from=-3 338 | activation=linear 339 | 340 | 341 | [convolutional] 342 | batch_normalize=1 343 | filters=256 344 | size=1 345 | stride=1 346 | pad=1 347 | activation=leaky 348 | 349 | [convolutional] 350 | batch_normalize=1 351 | filters=512 352 | size=3 353 | stride=1 354 | pad=1 355 | activation=leaky 356 | 357 | [shortcut] 358 | from=-3 359 | activation=linear 360 | 361 | 362 | [convolutional] 363 | batch_normalize=1 364 | filters=256 365 | size=1 366 | stride=1 367 | pad=1 368 | activation=leaky 369 | 370 | [convolutional] 371 | batch_normalize=1 372 | filters=512 373 | size=3 374 | stride=1 375 | pad=1 376 | activation=leaky 377 | 378 | [shortcut] 379 | from=-3 380 | activation=linear 381 | 382 | [convolutional] 383 | batch_normalize=1 384 | filters=256 385 | size=1 386 | stride=1 387 | pad=1 388 | activation=leaky 389 | 390 | [convolutional] 391 | batch_normalize=1 392 | filters=512 393 | size=3 394 | stride=1 395 | pad=1 396 | activation=leaky 397 | 398 | [shortcut] 399 | from=-3 400 | activation=linear 401 | 402 | 403 | [convolutional] 404 | batch_normalize=1 405 | filters=256 406 | size=1 407 | stride=1 408 | pad=1 409 | activation=leaky 410 | 411 | [convolutional] 412 | batch_normalize=1 413 | filters=512 414 | size=3 415 | stride=1 416 | pad=1 417 | activation=leaky 418 | 419 | [shortcut] 420 | from=-3 421 | activation=linear 422 | 423 | 424 | [convolutional] 425 | batch_normalize=1 426 | filters=256 427 | size=1 428 | stride=1 429 | pad=1 430 | activation=leaky 431 | 432 | [convolutional] 433 | batch_normalize=1 434 | filters=512 435 | size=3 436 | stride=1 437 | pad=1 438 | activation=leaky 439 | 440 | [shortcut] 441 | from=-3 442 | activation=linear 443 | 444 | [convolutional] 445 | batch_normalize=1 446 | filters=256 447 | size=1 448 | stride=1 449 | pad=1 450 | activation=leaky 451 | 452 | [convolutional] 453 | batch_normalize=1 454 | filters=512 455 | size=3 456 | stride=1 457 | pad=1 458 | activation=leaky 459 | 460 | [shortcut] 461 | from=-3 462 | activation=linear 463 | 464 | # Downsample 465 | 466 | [convolutional] 467 | batch_normalize=1 468 | filters=1024 469 | size=3 470 | stride=2 471 | pad=1 472 | activation=leaky 473 | 474 | [convolutional] 475 | batch_normalize=1 476 | filters=512 477 | size=1 478 | stride=1 479 | pad=1 480 | activation=leaky 481 | 482 | [convolutional] 483 | batch_normalize=1 484 | filters=1024 485 | size=3 486 | stride=1 487 | pad=1 488 | activation=leaky 489 | 490 | [shortcut] 491 | from=-3 492 | activation=linear 493 | 494 | [convolutional] 495 | batch_normalize=1 496 | filters=512 497 | size=1 498 | stride=1 499 | pad=1 500 | activation=leaky 501 | 502 | [convolutional] 503 | batch_normalize=1 504 | filters=1024 505 | size=3 506 | stride=1 507 | pad=1 508 | activation=leaky 509 | 510 | [shortcut] 511 | from=-3 512 | activation=linear 513 | 514 | [convolutional] 515 | batch_normalize=1 516 | filters=512 517 | size=1 518 | stride=1 519 | pad=1 520 | activation=leaky 521 | 522 | [convolutional] 523 | batch_normalize=1 524 | filters=1024 525 | size=3 526 | stride=1 527 | pad=1 528 | activation=leaky 529 | 530 | [shortcut] 531 | from=-3 532 | activation=linear 533 | 534 | [convolutional] 535 | batch_normalize=1 536 | filters=512 537 | size=1 538 | stride=1 539 | pad=1 540 | activation=leaky 541 | 542 | [convolutional] 543 | batch_normalize=1 544 | filters=1024 545 | size=3 546 | stride=1 547 | pad=1 548 | activation=leaky 549 | 550 | [shortcut] 551 | from=-3 552 | activation=linear 553 | 554 | ###################### 555 | 556 | [convolutional] 557 | batch_normalize=1 558 | filters=512 559 | size=1 560 | stride=1 561 | pad=1 562 | activation=leaky 563 | 564 | [convolutional] 565 | batch_normalize=1 566 | size=3 567 | stride=1 568 | pad=1 569 | filters=1024 570 | activation=leaky 571 | 572 | [convolutional] 573 | batch_normalize=1 574 | filters=512 575 | size=1 576 | stride=1 577 | pad=1 578 | activation=leaky 579 | 580 | [convolutional] 581 | batch_normalize=1 582 | size=3 583 | stride=1 584 | pad=1 585 | filters=1024 586 | activation=leaky 587 | 588 | [convolutional] 589 | batch_normalize=1 590 | filters=512 591 | size=1 592 | stride=1 593 | pad=1 594 | activation=leaky 595 | 596 | [convolutional] 597 | batch_normalize=1 598 | size=3 599 | stride=1 600 | pad=1 601 | filters=1024 602 | activation=leaky 603 | 604 | [convolutional] 605 | size=1 606 | stride=1 607 | pad=1 608 | filters=$(expr 3 \* $(expr $NUM_CLASSES \+ 5)) 609 | activation=linear 610 | 611 | 612 | [yolo] 613 | mask = 6,7,8 614 | anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 615 | classes=$NUM_CLASSES 616 | num=9 617 | jitter=.3 618 | ignore_thresh = .7 619 | truth_thresh = 1 620 | random=1 621 | 622 | 623 | [route] 624 | layers = -4 625 | 626 | [convolutional] 627 | batch_normalize=1 628 | filters=256 629 | size=1 630 | stride=1 631 | pad=1 632 | activation=leaky 633 | 634 | [upsample] 635 | stride=2 636 | 637 | [route] 638 | layers = -1, 61 639 | 640 | 641 | 642 | [convolutional] 643 | batch_normalize=1 644 | filters=256 645 | size=1 646 | stride=1 647 | pad=1 648 | activation=leaky 649 | 650 | [convolutional] 651 | batch_normalize=1 652 | size=3 653 | stride=1 654 | pad=1 655 | filters=512 656 | activation=leaky 657 | 658 | [convolutional] 659 | batch_normalize=1 660 | filters=256 661 | size=1 662 | stride=1 663 | pad=1 664 | activation=leaky 665 | 666 | [convolutional] 667 | batch_normalize=1 668 | size=3 669 | stride=1 670 | pad=1 671 | filters=512 672 | activation=leaky 673 | 674 | [convolutional] 675 | batch_normalize=1 676 | filters=256 677 | size=1 678 | stride=1 679 | pad=1 680 | activation=leaky 681 | 682 | [convolutional] 683 | batch_normalize=1 684 | size=3 685 | stride=1 686 | pad=1 687 | filters=512 688 | activation=leaky 689 | 690 | [convolutional] 691 | size=1 692 | stride=1 693 | pad=1 694 | filters=$(expr 3 \* $(expr $NUM_CLASSES \+ 5)) 695 | activation=linear 696 | 697 | 698 | [yolo] 699 | mask = 3,4,5 700 | anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 701 | classes=$NUM_CLASSES 702 | num=9 703 | jitter=.3 704 | ignore_thresh = .7 705 | truth_thresh = 1 706 | random=1 707 | 708 | 709 | 710 | [route] 711 | layers = -4 712 | 713 | [convolutional] 714 | batch_normalize=1 715 | filters=128 716 | size=1 717 | stride=1 718 | pad=1 719 | activation=leaky 720 | 721 | [upsample] 722 | stride=2 723 | 724 | [route] 725 | layers = -1, 36 726 | 727 | 728 | 729 | [convolutional] 730 | batch_normalize=1 731 | filters=128 732 | size=1 733 | stride=1 734 | pad=1 735 | activation=leaky 736 | 737 | [convolutional] 738 | batch_normalize=1 739 | size=3 740 | stride=1 741 | pad=1 742 | filters=256 743 | activation=leaky 744 | 745 | [convolutional] 746 | batch_normalize=1 747 | filters=128 748 | size=1 749 | stride=1 750 | pad=1 751 | activation=leaky 752 | 753 | [convolutional] 754 | batch_normalize=1 755 | size=3 756 | stride=1 757 | pad=1 758 | filters=256 759 | activation=leaky 760 | 761 | [convolutional] 762 | batch_normalize=1 763 | filters=128 764 | size=1 765 | stride=1 766 | pad=1 767 | activation=leaky 768 | 769 | [convolutional] 770 | batch_normalize=1 771 | size=3 772 | stride=1 773 | pad=1 774 | filters=256 775 | activation=leaky 776 | 777 | [convolutional] 778 | size=1 779 | stride=1 780 | pad=1 781 | filters=$(expr 3 \* $(expr $NUM_CLASSES \+ 5)) 782 | activation=linear 783 | 784 | 785 | [yolo] 786 | mask = 0,1,2 787 | anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326 788 | classes=$NUM_CLASSES 789 | num=9 790 | jitter=.3 791 | ignore_thresh = .7 792 | truth_thresh = 1 793 | random=1 794 | " >> yolov3-custom.cfg 795 | -------------------------------------------------------------------------------- /utils/utils.py: -------------------------------------------------------------------------------- 1 | from __future__ import division 2 | import math 3 | import time 4 | import tqdm 5 | import torch 6 | import torch.nn as nn 7 | import torch.nn.functional as F 8 | from torch.autograd import Variable 9 | import numpy as np 10 | import matplotlib.pyplot as plt 11 | import matplotlib.patches as patches 12 | 13 | 14 | def to_cpu(tensor): 15 | return tensor.detach().cpu() 16 | 17 | 18 | def load_classes(path): 19 | """ 20 | Loads class labels at 'path' 21 | """ 22 | fp = open(path, "r") 23 | names = fp.read().split("\n")[:-1] 24 | return names 25 | 26 | 27 | def weights_init_normal(m): 28 | classname = m.__class__.__name__ 29 | if classname.find("Conv") != -1: 30 | torch.nn.init.normal_(m.weight.data, 0.0, 0.02) 31 | elif classname.find("BatchNorm2d") != -1: 32 | torch.nn.init.normal_(m.weight.data, 1.0, 0.02) 33 | torch.nn.init.constant_(m.bias.data, 0.0) 34 | 35 | 36 | def rescale_boxes(boxes, current_dim, original_shape): 37 | """ Rescales bounding boxes to the original shape """ 38 | orig_h, orig_w = original_shape 39 | # The amount of padding that was added 40 | pad_x = max(orig_h - orig_w, 0) * (current_dim / max(original_shape)) 41 | pad_y = max(orig_w - orig_h, 0) * (current_dim / max(original_shape)) 42 | # Image height and width after padding is removed 43 | unpad_h = current_dim - pad_y 44 | unpad_w = current_dim - pad_x 45 | # Rescale bounding boxes to dimension of original image 46 | boxes[:, 0] = ((boxes[:, 0] - pad_x // 2) / unpad_w) * orig_w 47 | boxes[:, 1] = ((boxes[:, 1] - pad_y // 2) / unpad_h) * orig_h 48 | boxes[:, 2] = ((boxes[:, 2] - pad_x // 2) / unpad_w) * orig_w 49 | boxes[:, 3] = ((boxes[:, 3] - pad_y // 2) / unpad_h) * orig_h 50 | return boxes 51 | 52 | 53 | def xywh2xyxy(x): 54 | y = x.new(x.shape) 55 | y[..., 0] = x[..., 0] - x[..., 2] / 2 56 | y[..., 1] = x[..., 1] - x[..., 3] / 2 57 | y[..., 2] = x[..., 0] + x[..., 2] / 2 58 | y[..., 3] = x[..., 1] + x[..., 3] / 2 59 | return y 60 | 61 | 62 | def ap_per_class(tp, conf, pred_cls, target_cls): 63 | """ Compute the average precision, given the recall and precision curves. 64 | Source: https://github.com/rafaelpadilla/Object-Detection-Metrics. 65 | # Arguments 66 | tp: True positives (list). 67 | conf: Objectness value from 0-1 (list). 68 | pred_cls: Predicted object classes (list). 69 | target_cls: True object classes (list). 70 | # Returns 71 | The average precision as computed in py-faster-rcnn. 72 | """ 73 | 74 | # Sort by objectness 75 | i = np.argsort(-conf) 76 | tp, conf, pred_cls = tp[i], conf[i], pred_cls[i] 77 | 78 | # Find unique classes 79 | unique_classes = np.unique(target_cls) 80 | 81 | # Create Precision-Recall curve and compute AP for each class 82 | ap, p, r = [], [], [] 83 | for c in tqdm.tqdm(unique_classes, desc="Computing AP"): 84 | i = pred_cls == c 85 | n_gt = (target_cls == c).sum() # Number of ground truth objects 86 | n_p = i.sum() # Number of predicted objects 87 | 88 | if n_p == 0 and n_gt == 0: 89 | continue 90 | elif n_p == 0 or n_gt == 0: 91 | ap.append(0) 92 | r.append(0) 93 | p.append(0) 94 | else: 95 | # Accumulate FPs and TPs 96 | fpc = (1 - tp[i]).cumsum() 97 | tpc = (tp[i]).cumsum() 98 | 99 | # Recall 100 | recall_curve = tpc / (n_gt + 1e-16) 101 | r.append(recall_curve[-1]) 102 | 103 | # Precision 104 | precision_curve = tpc / (tpc + fpc) 105 | p.append(precision_curve[-1]) 106 | 107 | # AP from recall-precision curve 108 | ap.append(compute_ap(recall_curve, precision_curve)) 109 | 110 | # Compute F1 score (harmonic mean of precision and recall) 111 | p, r, ap = np.array(p), np.array(r), np.array(ap) 112 | f1 = 2 * p * r / (p + r + 1e-16) 113 | 114 | return p, r, ap, f1, unique_classes.astype("int32") 115 | 116 | 117 | def compute_ap(recall, precision): 118 | """ Compute the average precision, given the recall and precision curves. 119 | Code originally from https://github.com/rbgirshick/py-faster-rcnn. 120 | 121 | # Arguments 122 | recall: The recall curve (list). 123 | precision: The precision curve (list). 124 | # Returns 125 | The average precision as computed in py-faster-rcnn. 126 | """ 127 | # correct AP calculation 128 | # first append sentinel values at the end 129 | mrec = np.concatenate(([0.0], recall, [1.0])) 130 | mpre = np.concatenate(([0.0], precision, [0.0])) 131 | 132 | # compute the precision envelope 133 | for i in range(mpre.size - 1, 0, -1): 134 | mpre[i - 1] = np.maximum(mpre[i - 1], mpre[i]) 135 | 136 | # to calculate area under PR curve, look for points 137 | # where X axis (recall) changes value 138 | i = np.where(mrec[1:] != mrec[:-1])[0] 139 | 140 | # and sum (\Delta recall) * prec 141 | ap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1]) 142 | return ap 143 | 144 | 145 | def get_batch_statistics(outputs, targets, iou_threshold): 146 | """ Compute true positives, predicted scores and predicted labels per sample """ 147 | batch_metrics = [] 148 | for sample_i in range(len(outputs)): 149 | 150 | if outputs[sample_i] is None: 151 | continue 152 | 153 | output = outputs[sample_i] 154 | pred_boxes = output[:, :4] 155 | pred_scores = output[:, 4] 156 | pred_labels = output[:, -1] 157 | 158 | true_positives = np.zeros(pred_boxes.shape[0]) 159 | 160 | annotations = targets[targets[:, 0] == sample_i][:, 1:] 161 | target_labels = annotations[:, 0] if len(annotations) else [] 162 | if len(annotations): 163 | detected_boxes = [] 164 | target_boxes = annotations[:, 1:] 165 | 166 | for pred_i, (pred_box, pred_label) in enumerate(zip(pred_boxes, pred_labels)): 167 | 168 | # If targets are found break 169 | if len(detected_boxes) == len(annotations): 170 | break 171 | 172 | # Ignore if label is not one of the target labels 173 | if pred_label not in target_labels: 174 | continue 175 | 176 | iou, box_index = bbox_iou(pred_box.unsqueeze(0), target_boxes).max(0) 177 | if iou >= iou_threshold and box_index not in detected_boxes: 178 | true_positives[pred_i] = 1 179 | detected_boxes += [box_index] 180 | batch_metrics.append([true_positives, pred_scores, pred_labels]) 181 | return batch_metrics 182 | 183 | 184 | def bbox_wh_iou(wh1, wh2): 185 | wh2 = wh2.t() 186 | w1, h1 = wh1[0], wh1[1] 187 | w2, h2 = wh2[0], wh2[1] 188 | inter_area = torch.min(w1, w2) * torch.min(h1, h2) 189 | union_area = (w1 * h1 + 1e-16) + w2 * h2 - inter_area 190 | return inter_area / union_area 191 | 192 | 193 | def bbox_iou(box1, box2, x1y1x2y2=True): 194 | """ 195 | Returns the IoU of two bounding boxes 196 | """ 197 | if not x1y1x2y2: 198 | # Transform from center and width to exact coordinates 199 | b1_x1, b1_x2 = box1[:, 0] - box1[:, 2] / 2, box1[:, 0] + box1[:, 2] / 2 200 | b1_y1, b1_y2 = box1[:, 1] - box1[:, 3] / 2, box1[:, 1] + box1[:, 3] / 2 201 | b2_x1, b2_x2 = box2[:, 0] - box2[:, 2] / 2, box2[:, 0] + box2[:, 2] / 2 202 | b2_y1, b2_y2 = box2[:, 1] - box2[:, 3] / 2, box2[:, 1] + box2[:, 3] / 2 203 | else: 204 | # Get the coordinates of bounding boxes 205 | b1_x1, b1_y1, b1_x2, b1_y2 = box1[:, 0], box1[:, 1], box1[:, 2], box1[:, 3] 206 | b2_x1, b2_y1, b2_x2, b2_y2 = box2[:, 0], box2[:, 1], box2[:, 2], box2[:, 3] 207 | 208 | # get the corrdinates of the intersection rectangle 209 | inter_rect_x1 = torch.max(b1_x1, b2_x1) 210 | inter_rect_y1 = torch.max(b1_y1, b2_y1) 211 | inter_rect_x2 = torch.min(b1_x2, b2_x2) 212 | inter_rect_y2 = torch.min(b1_y2, b2_y2) 213 | # Intersection area 214 | inter_area = torch.clamp(inter_rect_x2 - inter_rect_x1 + 1, min=0) * torch.clamp( 215 | inter_rect_y2 - inter_rect_y1 + 1, min=0 216 | ) 217 | # Union Area 218 | b1_area = (b1_x2 - b1_x1 + 1) * (b1_y2 - b1_y1 + 1) 219 | b2_area = (b2_x2 - b2_x1 + 1) * (b2_y2 - b2_y1 + 1) 220 | 221 | iou = inter_area / (b1_area + b2_area - inter_area + 1e-16) 222 | 223 | return iou 224 | 225 | 226 | def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.4): 227 | """ 228 | Removes detections with lower object confidence score than 'conf_thres' and performs 229 | Non-Maximum Suppression to further filter detections. 230 | Returns detections with shape: 231 | (x1, y1, x2, y2, object_conf, class_score, class_pred) 232 | """ 233 | 234 | # From (center x, center y, width, height) to (x1, y1, x2, y2) 235 | prediction[..., :4] = xywh2xyxy(prediction[..., :4]) 236 | output = [None for _ in range(len(prediction))] 237 | for image_i, image_pred in enumerate(prediction): 238 | # Filter out confidence scores below threshold 239 | image_pred = image_pred[image_pred[:, 4] >= conf_thres] 240 | # If none are remaining => process next image 241 | if not image_pred.size(0): 242 | continue 243 | # Object confidence times class confidence 244 | score = image_pred[:, 4] * image_pred[:, 5:].max(1)[0] 245 | # Sort by it 246 | image_pred = image_pred[(-score).argsort()] 247 | class_confs, class_preds = image_pred[:, 5:].max(1, keepdim=True) 248 | detections = torch.cat((image_pred[:, :5], class_confs.float(), class_preds.float()), 1) 249 | # Perform non-maximum suppression 250 | keep_boxes = [] 251 | while detections.size(0): 252 | large_overlap = bbox_iou(detections[0, :4].unsqueeze(0), detections[:, :4]) > nms_thres 253 | label_match = detections[0, -1] == detections[:, -1] 254 | # Indices of boxes with lower confidence scores, large IOUs and matching labels 255 | invalid = large_overlap & label_match 256 | weights = detections[invalid, 4:5] 257 | # Merge overlapping bboxes by order of confidence 258 | detections[0, :4] = (weights * detections[invalid, :4]).sum(0) / weights.sum() 259 | keep_boxes += [detections[0]] 260 | detections = detections[~invalid] 261 | if keep_boxes: 262 | output[image_i] = torch.stack(keep_boxes) 263 | 264 | return output 265 | 266 | 267 | def build_targets(pred_boxes, pred_cls, target, anchors, ignore_thres): 268 | 269 | ByteTensor = torch.cuda.ByteTensor if pred_boxes.is_cuda else torch.ByteTensor 270 | FloatTensor = torch.cuda.FloatTensor if pred_boxes.is_cuda else torch.FloatTensor 271 | 272 | nB = pred_boxes.size(0) 273 | nA = pred_boxes.size(1) 274 | nC = pred_cls.size(-1) 275 | nG = pred_boxes.size(2) 276 | 277 | # Output tensors 278 | obj_mask = ByteTensor(nB, nA, nG, nG).fill_(0) 279 | noobj_mask = ByteTensor(nB, nA, nG, nG).fill_(1) 280 | class_mask = FloatTensor(nB, nA, nG, nG).fill_(0) 281 | iou_scores = FloatTensor(nB, nA, nG, nG).fill_(0) 282 | tx = FloatTensor(nB, nA, nG, nG).fill_(0) 283 | ty = FloatTensor(nB, nA, nG, nG).fill_(0) 284 | tw = FloatTensor(nB, nA, nG, nG).fill_(0) 285 | th = FloatTensor(nB, nA, nG, nG).fill_(0) 286 | tcls = FloatTensor(nB, nA, nG, nG, nC).fill_(0) 287 | 288 | # Convert to position relative to box 289 | target_boxes = target[:, 2:6] * nG 290 | gxy = target_boxes[:, :2] 291 | gwh = target_boxes[:, 2:] 292 | # Get anchors with best iou 293 | ious = torch.stack([bbox_wh_iou(anchor, gwh) for anchor in anchors]) 294 | best_ious, best_n = ious.max(0) 295 | # Separate target values 296 | b, target_labels = target[:, :2].long().t() 297 | gx, gy = gxy.t() 298 | gw, gh = gwh.t() 299 | gi, gj = gxy.long().t() 300 | # Set masks 301 | obj_mask[b, best_n, gj, gi] = 1 302 | noobj_mask[b, best_n, gj, gi] = 0 303 | 304 | # Set noobj mask to zero where iou exceeds ignore threshold 305 | for i, anchor_ious in enumerate(ious.t()): 306 | noobj_mask[b[i], anchor_ious > ignore_thres, gj[i], gi[i]] = 0 307 | 308 | # Coordinates 309 | tx[b, best_n, gj, gi] = gx - gx.floor() 310 | ty[b, best_n, gj, gi] = gy - gy.floor() 311 | # Width and height 312 | tw[b, best_n, gj, gi] = torch.log(gw / anchors[best_n][:, 0] + 1e-16) 313 | th[b, best_n, gj, gi] = torch.log(gh / anchors[best_n][:, 1] + 1e-16) 314 | # One-hot encoding of label 315 | tcls[b, best_n, gj, gi, target_labels] = 1 316 | # Compute label correctness and iou at best anchor 317 | class_mask[b, best_n, gj, gi] = (pred_cls[b, best_n, gj, gi].argmax(-1) == target_labels).float() 318 | iou_scores[b, best_n, gj, gi] = bbox_iou(pred_boxes[b, best_n, gj, gi], target_boxes, x1y1x2y2=False) 319 | 320 | tconf = obj_mask.float() 321 | return iou_scores, class_mask, obj_mask, noobj_mask, tx, ty, tw, th, tcls, tconf 322 | -------------------------------------------------------------------------------- /train.txt: -------------------------------------------------------------------------------- 1 | data/JPEGImages/aircraft_100.jpg 2 | data/JPEGImages/aircraft_1001.jpg 3 | data/JPEGImages/aircraft_1005.jpg 4 | data/JPEGImages/aircraft_1006.jpg 5 | data/JPEGImages/aircraft_1009.jpg 6 | data/JPEGImages/aircraft_101.jpg 7 | data/JPEGImages/aircraft_1010.jpg 8 | data/JPEGImages/aircraft_1011.jpg 9 | data/JPEGImages/aircraft_1012.jpg 10 | data/JPEGImages/aircraft_1016.jpg 11 | data/JPEGImages/aircraft_1017.jpg 12 | data/JPEGImages/aircraft_1018.jpg 13 | data/JPEGImages/aircraft_102.jpg 14 | data/JPEGImages/aircraft_1021.jpg 15 | data/JPEGImages/aircraft_1023.jpg 16 | data/JPEGImages/aircraft_1026.jpg 17 | data/JPEGImages/aircraft_1028.jpg 18 | data/JPEGImages/aircraft_1031.jpg 19 | data/JPEGImages/aircraft_1032.jpg 20 | data/JPEGImages/aircraft_1033.jpg 21 | data/JPEGImages/aircraft_1035.jpg 22 | data/JPEGImages/aircraft_1039.jpg 23 | data/JPEGImages/aircraft_104.jpg 24 | data/JPEGImages/aircraft_1041.jpg 25 | data/JPEGImages/aircraft_105.jpg 26 | data/JPEGImages/aircraft_1052.jpg 27 | data/JPEGImages/aircraft_1056.jpg 28 | data/JPEGImages/aircraft_1060.jpg 29 | data/JPEGImages/aircraft_1061.jpg 30 | data/JPEGImages/aircraft_1063.jpg 31 | data/JPEGImages/aircraft_1064.jpg 32 | data/JPEGImages/aircraft_1066.jpg 33 | data/JPEGImages/aircraft_1067.jpg 34 | data/JPEGImages/aircraft_1068.jpg 35 | data/JPEGImages/aircraft_1069.jpg 36 | data/JPEGImages/aircraft_107.jpg 37 | data/JPEGImages/aircraft_1071.jpg 38 | data/JPEGImages/aircraft_1076.jpg 39 | data/JPEGImages/aircraft_1078.jpg 40 | data/JPEGImages/aircraft_1081.jpg 41 | data/JPEGImages/aircraft_1085.jpg 42 | data/JPEGImages/aircraft_1087.jpg 43 | data/JPEGImages/aircraft_1091.jpg 44 | data/JPEGImages/aircraft_1095.jpg 45 | data/JPEGImages/aircraft_1097.jpg 46 | data/JPEGImages/aircraft_1098.jpg 47 | data/JPEGImages/aircraft_1099.jpg 48 | data/JPEGImages/aircraft_110.jpg 49 | data/JPEGImages/aircraft_1102.jpg 50 | data/JPEGImages/aircraft_1104.jpg 51 | data/JPEGImages/aircraft_1105.jpg 52 | data/JPEGImages/aircraft_1108.jpg 53 | data/JPEGImages/aircraft_1111.jpg 54 | data/JPEGImages/aircraft_1113.jpg 55 | data/JPEGImages/aircraft_1114.jpg 56 | data/JPEGImages/aircraft_1115.jpg 57 | data/JPEGImages/aircraft_1118.jpg 58 | data/JPEGImages/aircraft_1121.jpg 59 | data/JPEGImages/aircraft_1124.jpg 60 | data/JPEGImages/aircraft_1130.jpg 61 | data/JPEGImages/aircraft_1132.jpg 62 | data/JPEGImages/aircraft_1134.jpg 63 | data/JPEGImages/aircraft_1137.jpg 64 | data/JPEGImages/aircraft_114.jpg 65 | data/JPEGImages/aircraft_116.jpg 66 | data/JPEGImages/aircraft_119.jpg 67 | data/JPEGImages/aircraft_120.jpg 68 | data/JPEGImages/aircraft_123.jpg 69 | data/JPEGImages/aircraft_127.jpg 70 | data/JPEGImages/aircraft_128.jpg 71 | data/JPEGImages/aircraft_129.jpg 72 | data/JPEGImages/aircraft_139.jpg 73 | data/JPEGImages/aircraft_14.jpg 74 | data/JPEGImages/aircraft_142.jpg 75 | data/JPEGImages/aircraft_145.jpg 76 | data/JPEGImages/aircraft_146.jpg 77 | data/JPEGImages/aircraft_149.jpg 78 | data/JPEGImages/aircraft_151.jpg 79 | data/JPEGImages/aircraft_152.jpg 80 | data/JPEGImages/aircraft_155.jpg 81 | data/JPEGImages/aircraft_158.jpg 82 | data/JPEGImages/aircraft_162.jpg 83 | data/JPEGImages/aircraft_164.jpg 84 | data/JPEGImages/aircraft_168.jpg 85 | data/JPEGImages/aircraft_175.jpg 86 | data/JPEGImages/aircraft_181.jpg 87 | data/JPEGImages/aircraft_185.jpg 88 | data/JPEGImages/aircraft_19.jpg 89 | data/JPEGImages/aircraft_190.jpg 90 | data/JPEGImages/aircraft_192.jpg 91 | data/JPEGImages/aircraft_194.jpg 92 | data/JPEGImages/aircraft_195.jpg 93 | data/JPEGImages/aircraft_198.jpg 94 | data/JPEGImages/aircraft_199.jpg 95 | data/JPEGImages/aircraft_202.jpg 96 | data/JPEGImages/aircraft_205.jpg 97 | data/JPEGImages/aircraft_21.jpg 98 | data/JPEGImages/aircraft_213.jpg 99 | data/JPEGImages/aircraft_215.jpg 100 | data/JPEGImages/aircraft_216.jpg 101 | data/JPEGImages/aircraft_218.jpg 102 | data/JPEGImages/aircraft_219.jpg 103 | data/JPEGImages/aircraft_22.jpg 104 | data/JPEGImages/aircraft_220.jpg 105 | data/JPEGImages/aircraft_223.jpg 106 | data/JPEGImages/aircraft_225.jpg 107 | data/JPEGImages/aircraft_227.jpg 108 | data/JPEGImages/aircraft_229.jpg 109 | data/JPEGImages/aircraft_23.jpg 110 | data/JPEGImages/aircraft_233.jpg 111 | data/JPEGImages/aircraft_239.jpg 112 | data/JPEGImages/aircraft_242.jpg 113 | data/JPEGImages/aircraft_244.jpg 114 | data/JPEGImages/aircraft_247.jpg 115 | data/JPEGImages/aircraft_260.jpg 116 | data/JPEGImages/aircraft_269.jpg 117 | data/JPEGImages/aircraft_27.jpg 118 | data/JPEGImages/aircraft_271.jpg 119 | data/JPEGImages/aircraft_275.jpg 120 | data/JPEGImages/aircraft_276.jpg 121 | data/JPEGImages/aircraft_277.jpg 122 | data/JPEGImages/aircraft_278.jpg 123 | data/JPEGImages/aircraft_283.jpg 124 | data/JPEGImages/aircraft_284.jpg 125 | data/JPEGImages/aircraft_287.jpg 126 | data/JPEGImages/aircraft_289.jpg 127 | data/JPEGImages/aircraft_290.jpg 128 | data/JPEGImages/aircraft_291.jpg 129 | data/JPEGImages/aircraft_293.jpg 130 | data/JPEGImages/aircraft_295.jpg 131 | data/JPEGImages/aircraft_30.jpg 132 | data/JPEGImages/aircraft_300.jpg 133 | data/JPEGImages/aircraft_302.jpg 134 | data/JPEGImages/aircraft_308.jpg 135 | data/JPEGImages/aircraft_313.jpg 136 | data/JPEGImages/aircraft_315.jpg 137 | data/JPEGImages/aircraft_319.jpg 138 | data/JPEGImages/aircraft_32.jpg 139 | data/JPEGImages/aircraft_322.jpg 140 | data/JPEGImages/aircraft_323.jpg 141 | data/JPEGImages/aircraft_33.jpg 142 | data/JPEGImages/aircraft_332.jpg 143 | data/JPEGImages/aircraft_34.jpg 144 | data/JPEGImages/aircraft_343.jpg 145 | data/JPEGImages/aircraft_344.jpg 146 | data/JPEGImages/aircraft_345.jpg 147 | data/JPEGImages/aircraft_346.jpg 148 | data/JPEGImages/aircraft_347.jpg 149 | data/JPEGImages/aircraft_348.jpg 150 | data/JPEGImages/aircraft_349.jpg 151 | data/JPEGImages/aircraft_351.jpg 152 | data/JPEGImages/aircraft_362.jpg 153 | data/JPEGImages/aircraft_364.jpg 154 | data/JPEGImages/aircraft_366.jpg 155 | data/JPEGImages/aircraft_373.jpg 156 | data/JPEGImages/aircraft_381.jpg 157 | data/JPEGImages/aircraft_383.jpg 158 | data/JPEGImages/aircraft_385.jpg 159 | data/JPEGImages/aircraft_395.jpg 160 | data/JPEGImages/aircraft_396.jpg 161 | data/JPEGImages/aircraft_4.jpg 162 | data/JPEGImages/aircraft_400.jpg 163 | data/JPEGImages/aircraft_401.jpg 164 | data/JPEGImages/aircraft_404.jpg 165 | data/JPEGImages/aircraft_405.jpg 166 | data/JPEGImages/aircraft_406.jpg 167 | data/JPEGImages/aircraft_410.jpg 168 | data/JPEGImages/aircraft_411.jpg 169 | data/JPEGImages/aircraft_415.jpg 170 | data/JPEGImages/aircraft_423.jpg 171 | data/JPEGImages/aircraft_428.jpg 172 | data/JPEGImages/aircraft_431.jpg 173 | data/JPEGImages/aircraft_432.jpg 174 | data/JPEGImages/aircraft_433.jpg 175 | data/JPEGImages/aircraft_435.jpg 176 | data/JPEGImages/aircraft_436.jpg 177 | data/JPEGImages/aircraft_438.jpg 178 | data/JPEGImages/aircraft_439.jpg 179 | data/JPEGImages/aircraft_444.jpg 180 | data/JPEGImages/aircraft_445.jpg 181 | data/JPEGImages/aircraft_447.jpg 182 | data/JPEGImages/aircraft_450.jpg 183 | data/JPEGImages/aircraft_452.jpg 184 | data/JPEGImages/aircraft_461.jpg 185 | data/JPEGImages/aircraft_464.jpg 186 | data/JPEGImages/aircraft_467.jpg 187 | data/JPEGImages/aircraft_471.jpg 188 | data/JPEGImages/aircraft_472.jpg 189 | data/JPEGImages/aircraft_474.jpg 190 | data/JPEGImages/aircraft_477.jpg 191 | data/JPEGImages/aircraft_479.jpg 192 | data/JPEGImages/aircraft_480.jpg 193 | data/JPEGImages/aircraft_485.jpg 194 | data/JPEGImages/aircraft_486.jpg 195 | data/JPEGImages/aircraft_487.jpg 196 | data/JPEGImages/aircraft_489.jpg 197 | data/JPEGImages/aircraft_49.jpg 198 | data/JPEGImages/aircraft_490.jpg 199 | data/JPEGImages/aircraft_491.jpg 200 | data/JPEGImages/aircraft_496.jpg 201 | data/JPEGImages/aircraft_497.jpg 202 | data/JPEGImages/aircraft_504.jpg 203 | data/JPEGImages/aircraft_506.jpg 204 | data/JPEGImages/aircraft_507.jpg 205 | data/JPEGImages/aircraft_508.jpg 206 | data/JPEGImages/aircraft_509.jpg 207 | data/JPEGImages/aircraft_510.jpg 208 | data/JPEGImages/aircraft_516.jpg 209 | data/JPEGImages/aircraft_520.jpg 210 | data/JPEGImages/aircraft_521.jpg 211 | data/JPEGImages/aircraft_523.jpg 212 | data/JPEGImages/aircraft_524.jpg 213 | data/JPEGImages/aircraft_525.jpg 214 | data/JPEGImages/aircraft_526.jpg 215 | data/JPEGImages/aircraft_527.jpg 216 | data/JPEGImages/aircraft_536.jpg 217 | data/JPEGImages/aircraft_538.jpg 218 | data/JPEGImages/aircraft_539.jpg 219 | data/JPEGImages/aircraft_543.jpg 220 | data/JPEGImages/aircraft_544.jpg 221 | data/JPEGImages/aircraft_550.jpg 222 | data/JPEGImages/aircraft_559.jpg 223 | data/JPEGImages/aircraft_569.jpg 224 | data/JPEGImages/aircraft_57.jpg 225 | data/JPEGImages/aircraft_572.jpg 226 | data/JPEGImages/aircraft_575.jpg 227 | data/JPEGImages/aircraft_579.jpg 228 | data/JPEGImages/aircraft_580.jpg 229 | data/JPEGImages/aircraft_581.jpg 230 | data/JPEGImages/aircraft_582.jpg 231 | data/JPEGImages/aircraft_583.jpg 232 | data/JPEGImages/aircraft_589.jpg 233 | data/JPEGImages/aircraft_59.jpg 234 | data/JPEGImages/aircraft_591.jpg 235 | data/JPEGImages/aircraft_593.jpg 236 | data/JPEGImages/aircraft_601.jpg 237 | data/JPEGImages/aircraft_608.jpg 238 | data/JPEGImages/aircraft_609.jpg 239 | data/JPEGImages/aircraft_613.jpg 240 | data/JPEGImages/aircraft_615.jpg 241 | data/JPEGImages/aircraft_617.jpg 242 | data/JPEGImages/aircraft_619.jpg 243 | data/JPEGImages/aircraft_622.jpg 244 | data/JPEGImages/aircraft_623.jpg 245 | data/JPEGImages/aircraft_626.jpg 246 | data/JPEGImages/aircraft_627.jpg 247 | data/JPEGImages/aircraft_628.jpg 248 | data/JPEGImages/aircraft_632.jpg 249 | data/JPEGImages/aircraft_637.jpg 250 | data/JPEGImages/aircraft_640.jpg 251 | data/JPEGImages/aircraft_643.jpg 252 | data/JPEGImages/aircraft_644.jpg 253 | data/JPEGImages/aircraft_645.jpg 254 | data/JPEGImages/aircraft_646.jpg 255 | data/JPEGImages/aircraft_648.jpg 256 | data/JPEGImages/aircraft_651.jpg 257 | data/JPEGImages/aircraft_654.jpg 258 | data/JPEGImages/aircraft_656.jpg 259 | data/JPEGImages/aircraft_661.jpg 260 | data/JPEGImages/aircraft_662.jpg 261 | data/JPEGImages/aircraft_666.jpg 262 | data/JPEGImages/aircraft_667.jpg 263 | data/JPEGImages/aircraft_676.jpg 264 | data/JPEGImages/aircraft_677.jpg 265 | data/JPEGImages/aircraft_678.jpg 266 | data/JPEGImages/aircraft_680.jpg 267 | data/JPEGImages/aircraft_682.jpg 268 | data/JPEGImages/aircraft_683.jpg 269 | data/JPEGImages/aircraft_684.jpg 270 | data/JPEGImages/aircraft_685.jpg 271 | data/JPEGImages/aircraft_688.jpg 272 | data/JPEGImages/aircraft_689.jpg 273 | data/JPEGImages/aircraft_69.jpg 274 | data/JPEGImages/aircraft_693.jpg 275 | data/JPEGImages/aircraft_698.jpg 276 | data/JPEGImages/aircraft_70.jpg 277 | data/JPEGImages/aircraft_700.jpg 278 | data/JPEGImages/aircraft_701.jpg 279 | data/JPEGImages/aircraft_703.jpg 280 | data/JPEGImages/aircraft_706.jpg 281 | data/JPEGImages/aircraft_712.jpg 282 | data/JPEGImages/aircraft_716.jpg 283 | data/JPEGImages/aircraft_719.jpg 284 | data/JPEGImages/aircraft_720.jpg 285 | data/JPEGImages/aircraft_721.jpg 286 | data/JPEGImages/aircraft_723.jpg 287 | data/JPEGImages/aircraft_726.jpg 288 | data/JPEGImages/aircraft_727.jpg 289 | data/JPEGImages/aircraft_728.jpg 290 | data/JPEGImages/aircraft_729.jpg 291 | data/JPEGImages/aircraft_731.jpg 292 | data/JPEGImages/aircraft_735.jpg 293 | data/JPEGImages/aircraft_738.jpg 294 | data/JPEGImages/aircraft_739.jpg 295 | data/JPEGImages/aircraft_740.jpg 296 | data/JPEGImages/aircraft_741.jpg 297 | data/JPEGImages/aircraft_742.jpg 298 | data/JPEGImages/aircraft_743.jpg 299 | data/JPEGImages/aircraft_744.jpg 300 | data/JPEGImages/aircraft_758.jpg 301 | data/JPEGImages/aircraft_77.jpg 302 | data/JPEGImages/aircraft_770.jpg 303 | data/JPEGImages/aircraft_772.jpg 304 | data/JPEGImages/aircraft_773.jpg 305 | data/JPEGImages/aircraft_780.jpg 306 | data/JPEGImages/aircraft_781.jpg 307 | data/JPEGImages/aircraft_783.jpg 308 | data/JPEGImages/aircraft_786.jpg 309 | data/JPEGImages/aircraft_787.jpg 310 | data/JPEGImages/aircraft_789.jpg 311 | data/JPEGImages/aircraft_79.jpg 312 | data/JPEGImages/aircraft_791.jpg 313 | data/JPEGImages/aircraft_796.jpg 314 | data/JPEGImages/aircraft_798.jpg 315 | data/JPEGImages/aircraft_799.jpg 316 | data/JPEGImages/aircraft_8.jpg 317 | data/JPEGImages/aircraft_80.jpg 318 | data/JPEGImages/aircraft_801.jpg 319 | data/JPEGImages/aircraft_802.jpg 320 | data/JPEGImages/aircraft_803.jpg 321 | data/JPEGImages/aircraft_804.jpg 322 | data/JPEGImages/aircraft_805.jpg 323 | data/JPEGImages/aircraft_807.jpg 324 | data/JPEGImages/aircraft_809.jpg 325 | data/JPEGImages/aircraft_810.jpg 326 | data/JPEGImages/aircraft_814.jpg 327 | data/JPEGImages/aircraft_818.jpg 328 | data/JPEGImages/aircraft_82.jpg 329 | data/JPEGImages/aircraft_820.jpg 330 | data/JPEGImages/aircraft_822.jpg 331 | data/JPEGImages/aircraft_824.jpg 332 | data/JPEGImages/aircraft_825.jpg 333 | data/JPEGImages/aircraft_826.jpg 334 | data/JPEGImages/aircraft_827.jpg 335 | data/JPEGImages/aircraft_828.jpg 336 | data/JPEGImages/aircraft_831.jpg 337 | data/JPEGImages/aircraft_832.jpg 338 | data/JPEGImages/aircraft_836.jpg 339 | data/JPEGImages/aircraft_844.jpg 340 | data/JPEGImages/aircraft_848.jpg 341 | data/JPEGImages/aircraft_851.jpg 342 | data/JPEGImages/aircraft_856.jpg 343 | data/JPEGImages/aircraft_858.jpg 344 | data/JPEGImages/aircraft_861.jpg 345 | data/JPEGImages/aircraft_862.jpg 346 | data/JPEGImages/aircraft_863.jpg 347 | data/JPEGImages/aircraft_864.jpg 348 | data/JPEGImages/aircraft_867.jpg 349 | data/JPEGImages/aircraft_868.jpg 350 | data/JPEGImages/aircraft_87.jpg 351 | data/JPEGImages/aircraft_874.jpg 352 | data/JPEGImages/aircraft_878.jpg 353 | data/JPEGImages/aircraft_88.jpg 354 | data/JPEGImages/aircraft_881.jpg 355 | data/JPEGImages/aircraft_883.jpg 356 | data/JPEGImages/aircraft_884.jpg 357 | data/JPEGImages/aircraft_885.jpg 358 | data/JPEGImages/aircraft_887.jpg 359 | data/JPEGImages/aircraft_894.jpg 360 | data/JPEGImages/aircraft_897.jpg 361 | data/JPEGImages/aircraft_90.jpg 362 | data/JPEGImages/aircraft_900.jpg 363 | data/JPEGImages/aircraft_902.jpg 364 | data/JPEGImages/aircraft_903.jpg 365 | data/JPEGImages/aircraft_904.jpg 366 | data/JPEGImages/aircraft_905.jpg 367 | data/JPEGImages/aircraft_907.jpg 368 | data/JPEGImages/aircraft_908.jpg 369 | data/JPEGImages/aircraft_912.jpg 370 | data/JPEGImages/aircraft_914.jpg 371 | data/JPEGImages/aircraft_916.jpg 372 | data/JPEGImages/aircraft_921.jpg 373 | data/JPEGImages/aircraft_923.jpg 374 | data/JPEGImages/aircraft_924.jpg 375 | data/JPEGImages/aircraft_925.jpg 376 | data/JPEGImages/aircraft_933.jpg 377 | data/JPEGImages/aircraft_939.jpg 378 | data/JPEGImages/aircraft_940.jpg 379 | data/JPEGImages/aircraft_943.jpg 380 | data/JPEGImages/aircraft_948.jpg 381 | data/JPEGImages/aircraft_949.jpg 382 | data/JPEGImages/aircraft_950.jpg 383 | data/JPEGImages/aircraft_953.jpg 384 | data/JPEGImages/aircraft_957.jpg 385 | data/JPEGImages/aircraft_962.jpg 386 | data/JPEGImages/aircraft_963.jpg 387 | data/JPEGImages/aircraft_964.jpg 388 | data/JPEGImages/aircraft_965.jpg 389 | data/JPEGImages/aircraft_966.jpg 390 | data/JPEGImages/aircraft_969.jpg 391 | data/JPEGImages/aircraft_973.jpg 392 | data/JPEGImages/aircraft_977.jpg 393 | data/JPEGImages/aircraft_978.jpg 394 | data/JPEGImages/aircraft_979.jpg 395 | data/JPEGImages/aircraft_98.jpg 396 | data/JPEGImages/aircraft_985.jpg 397 | data/JPEGImages/aircraft_986.jpg 398 | data/JPEGImages/aircraft_99.jpg 399 | data/JPEGImages/aircraft_993.jpg 400 | data/JPEGImages/aircraft_996.jpg 401 | data/JPEGImages/aircraft_997.jpg 402 | data/JPEGImages/aircraft_998.jpg 403 | -------------------------------------------------------------------------------- /models.py: -------------------------------------------------------------------------------- 1 | from __future__ import division 2 | 3 | import torch 4 | import torch.nn as nn 5 | import torch.nn.functional as F 6 | from torch.autograd import Variable 7 | import numpy as np 8 | 9 | from utils.parse_config import * 10 | from utils.utils import build_targets, to_cpu, non_max_suppression 11 | 12 | import matplotlib.pyplot as plt 13 | import matplotlib.patches as patches 14 | 15 | 16 | def create_modules(module_defs): 17 | """ 18 | Constructs module list of layer blocks from module configuration in module_defs 19 | """ 20 | hyperparams = module_defs.pop(0) 21 | output_filters = [int(hyperparams["channels"])] 22 | module_list = nn.ModuleList() 23 | for module_i, module_def in enumerate(module_defs): 24 | modules = nn.Sequential() 25 | 26 | if module_def["type"] == "convolutional": 27 | bn = int(module_def["batch_normalize"]) 28 | filters = int(module_def["filters"]) 29 | kernel_size = int(module_def["size"]) 30 | pad = (kernel_size - 1) // 2 31 | modules.add_module( 32 | f"conv_{module_i}", 33 | nn.Conv2d( 34 | in_channels=output_filters[-1], 35 | out_channels=filters, 36 | kernel_size=kernel_size, 37 | stride=int(module_def["stride"]), 38 | padding=pad, 39 | bias=not bn, 40 | ), 41 | ) 42 | if bn: 43 | modules.add_module(f"batch_norm_{module_i}", nn.BatchNorm2d(filters, momentum=0.9, eps=1e-5)) 44 | if module_def["activation"] == "leaky": 45 | modules.add_module(f"leaky_{module_i}", nn.LeakyReLU(0.1)) 46 | 47 | elif module_def["type"] == "maxpool": 48 | kernel_size = int(module_def["size"]) 49 | stride = int(module_def["stride"]) 50 | if kernel_size == 2 and stride == 1: 51 | modules.add_module(f"_debug_padding_{module_i}", nn.ZeroPad2d((0, 1, 0, 1))) 52 | maxpool = nn.MaxPool2d(kernel_size=kernel_size, stride=stride, padding=int((kernel_size - 1) // 2)) 53 | modules.add_module(f"maxpool_{module_i}", maxpool) 54 | 55 | elif module_def["type"] == "upsample": 56 | upsample = Upsample(scale_factor=int(module_def["stride"]), mode="nearest") 57 | modules.add_module(f"upsample_{module_i}", upsample) 58 | 59 | elif module_def["type"] == "route": 60 | layers = [int(x) for x in module_def["layers"].split(",")] 61 | filters = sum([output_filters[1:][i] for i in layers]) 62 | modules.add_module(f"route_{module_i}", EmptyLayer()) 63 | 64 | elif module_def["type"] == "shortcut": 65 | filters = output_filters[1:][int(module_def["from"])] 66 | modules.add_module(f"shortcut_{module_i}", EmptyLayer()) 67 | 68 | elif module_def["type"] == "yolo": 69 | anchor_idxs = [int(x) for x in module_def["mask"].split(",")] 70 | # Extract anchors 71 | anchors = [int(x) for x in module_def["anchors"].split(",")] 72 | anchors = [(anchors[i], anchors[i + 1]) for i in range(0, len(anchors), 2)] 73 | anchors = [anchors[i] for i in anchor_idxs] 74 | num_classes = int(module_def["classes"]) 75 | img_size = int(hyperparams["height"]) 76 | # Define detection layer 77 | yolo_layer = YOLOLayer(anchors, num_classes, img_size) 78 | modules.add_module(f"yolo_{module_i}", yolo_layer) 79 | # Register module list and number of output filters 80 | module_list.append(modules) 81 | output_filters.append(filters) 82 | 83 | return hyperparams, module_list 84 | 85 | 86 | class Upsample(nn.Module): 87 | """ nn.Upsample is deprecated """ 88 | 89 | def __init__(self, scale_factor, mode="nearest"): 90 | super(Upsample, self).__init__() 91 | self.scale_factor = scale_factor 92 | self.mode = mode 93 | 94 | def forward(self, x): 95 | x = F.interpolate(x, scale_factor=self.scale_factor, mode=self.mode) 96 | return x 97 | 98 | 99 | class EmptyLayer(nn.Module): 100 | """Placeholder for 'route' and 'shortcut' layers""" 101 | 102 | def __init__(self): 103 | super(EmptyLayer, self).__init__() 104 | 105 | 106 | class YOLOLayer(nn.Module): 107 | """Detection layer""" 108 | 109 | def __init__(self, anchors, num_classes, img_dim=416): 110 | super(YOLOLayer, self).__init__() 111 | self.anchors = anchors 112 | self.num_anchors = len(anchors) 113 | self.num_classes = num_classes 114 | self.ignore_thres = 0.5 115 | self.mse_loss = nn.MSELoss() 116 | self.bce_loss = nn.BCELoss() 117 | self.obj_scale = 1 118 | self.noobj_scale = 100 119 | self.metrics = {} 120 | self.img_dim = img_dim 121 | self.grid_size = 0 # grid size 122 | 123 | def compute_grid_offsets(self, grid_size, cuda=True): 124 | self.grid_size = grid_size 125 | g = self.grid_size 126 | FloatTensor = torch.cuda.FloatTensor if cuda else torch.FloatTensor 127 | self.stride = self.img_dim / self.grid_size 128 | # Calculate offsets for each grid 129 | self.grid_x = torch.arange(g).repeat(g, 1).view([1, 1, g, g]).type(FloatTensor) 130 | self.grid_y = torch.arange(g).repeat(g, 1).t().view([1, 1, g, g]).type(FloatTensor) 131 | self.scaled_anchors = FloatTensor([(a_w / self.stride, a_h / self.stride) for a_w, a_h in self.anchors]) 132 | self.anchor_w = self.scaled_anchors[:, 0:1].view((1, self.num_anchors, 1, 1)) 133 | self.anchor_h = self.scaled_anchors[:, 1:2].view((1, self.num_anchors, 1, 1)) 134 | 135 | def forward(self, x, targets=None, img_dim=None): 136 | 137 | # Tensors for cuda support 138 | FloatTensor = torch.cuda.FloatTensor if x.is_cuda else torch.FloatTensor 139 | LongTensor = torch.cuda.LongTensor if x.is_cuda else torch.LongTensor 140 | ByteTensor = torch.cuda.ByteTensor if x.is_cuda else torch.ByteTensor 141 | 142 | self.img_dim = img_dim 143 | num_samples = x.size(0) 144 | grid_size = x.size(2) 145 | 146 | prediction = ( 147 | x.view(num_samples, self.num_anchors, self.num_classes + 5, grid_size, grid_size) 148 | .permute(0, 1, 3, 4, 2) 149 | .contiguous() 150 | ) 151 | 152 | # Get outputs 153 | x = torch.sigmoid(prediction[..., 0]) # Center x 154 | y = torch.sigmoid(prediction[..., 1]) # Center y 155 | w = prediction[..., 2] # Width 156 | h = prediction[..., 3] # Height 157 | pred_conf = torch.sigmoid(prediction[..., 4]) # Conf 158 | pred_cls = torch.sigmoid(prediction[..., 5:]) # Cls pred. 159 | 160 | # If grid size does not match current we compute new offsets 161 | if grid_size != self.grid_size: 162 | self.compute_grid_offsets(grid_size, cuda=x.is_cuda) 163 | 164 | # Add offset and scale with anchors 165 | pred_boxes = FloatTensor(prediction[..., :4].shape) 166 | pred_boxes[..., 0] = x.data + self.grid_x 167 | pred_boxes[..., 1] = y.data + self.grid_y 168 | pred_boxes[..., 2] = torch.exp(w.data) * self.anchor_w 169 | pred_boxes[..., 3] = torch.exp(h.data) * self.anchor_h 170 | 171 | output = torch.cat( 172 | ( 173 | pred_boxes.view(num_samples, -1, 4) * self.stride, 174 | pred_conf.view(num_samples, -1, 1), 175 | pred_cls.view(num_samples, -1, self.num_classes), 176 | ), 177 | -1, 178 | ) 179 | 180 | if targets is None: 181 | return output, 0 182 | else: 183 | iou_scores, class_mask, obj_mask, noobj_mask, tx, ty, tw, th, tcls, tconf = build_targets( 184 | pred_boxes=pred_boxes, 185 | pred_cls=pred_cls, 186 | target=targets, 187 | anchors=self.scaled_anchors, 188 | ignore_thres=self.ignore_thres, 189 | ) 190 | 191 | # Loss : Mask outputs to ignore non-existing objects (except with conf. loss) 192 | loss_x = self.mse_loss(x[obj_mask], tx[obj_mask]) 193 | loss_y = self.mse_loss(y[obj_mask], ty[obj_mask]) 194 | loss_w = self.mse_loss(w[obj_mask], tw[obj_mask]) 195 | loss_h = self.mse_loss(h[obj_mask], th[obj_mask]) 196 | loss_conf_obj = self.bce_loss(pred_conf[obj_mask], tconf[obj_mask]) 197 | loss_conf_noobj = self.bce_loss(pred_conf[noobj_mask], tconf[noobj_mask]) 198 | loss_conf = self.obj_scale * loss_conf_obj + self.noobj_scale * loss_conf_noobj 199 | loss_cls = self.bce_loss(pred_cls[obj_mask], tcls[obj_mask]) 200 | total_loss = loss_x + loss_y + loss_w + loss_h + loss_conf + loss_cls 201 | 202 | # Metrics 203 | cls_acc = 100 * class_mask[obj_mask].mean() 204 | conf_obj = pred_conf[obj_mask].mean() 205 | conf_noobj = pred_conf[noobj_mask].mean() 206 | conf50 = (pred_conf > 0.5).float() 207 | iou50 = (iou_scores > 0.5).float() 208 | iou75 = (iou_scores > 0.75).float() 209 | detected_mask = conf50 * class_mask * tconf 210 | precision = torch.sum(iou50 * detected_mask) / (conf50.sum() + 1e-16) 211 | recall50 = torch.sum(iou50 * detected_mask) / (obj_mask.sum() + 1e-16) 212 | recall75 = torch.sum(iou75 * detected_mask) / (obj_mask.sum() + 1e-16) 213 | 214 | self.metrics = { 215 | "loss": to_cpu(total_loss).item(), 216 | "x": to_cpu(loss_x).item(), 217 | "y": to_cpu(loss_y).item(), 218 | "w": to_cpu(loss_w).item(), 219 | "h": to_cpu(loss_h).item(), 220 | "conf": to_cpu(loss_conf).item(), 221 | "cls": to_cpu(loss_cls).item(), 222 | "cls_acc": to_cpu(cls_acc).item(), 223 | "recall50": to_cpu(recall50).item(), 224 | "recall75": to_cpu(recall75).item(), 225 | "precision": to_cpu(precision).item(), 226 | "conf_obj": to_cpu(conf_obj).item(), 227 | "conf_noobj": to_cpu(conf_noobj).item(), 228 | "grid_size": grid_size, 229 | } 230 | 231 | return output, total_loss 232 | 233 | 234 | class Darknet(nn.Module): 235 | """YOLOv3 object detection model""" 236 | 237 | def __init__(self, config_path, img_size=416): 238 | super(Darknet, self).__init__() 239 | self.module_defs = parse_model_config(config_path) 240 | self.hyperparams, self.module_list = create_modules(self.module_defs) 241 | self.yolo_layers = [layer[0] for layer in self.module_list if hasattr(layer[0], "metrics")] 242 | self.img_size = img_size 243 | self.seen = 0 244 | self.header_info = np.array([0, 0, 0, self.seen, 0], dtype=np.int32) 245 | 246 | def forward(self, x, targets=None): 247 | img_dim = x.shape[2] 248 | loss = 0 249 | layer_outputs, yolo_outputs = [], [] 250 | for i, (module_def, module) in enumerate(zip(self.module_defs, self.module_list)): 251 | if module_def["type"] in ["convolutional", "upsample", "maxpool"]: 252 | x = module(x) 253 | elif module_def["type"] == "route": 254 | x = torch.cat([layer_outputs[int(layer_i)] for layer_i in module_def["layers"].split(",")], 1) 255 | elif module_def["type"] == "shortcut": 256 | layer_i = int(module_def["from"]) 257 | x = layer_outputs[-1] + layer_outputs[layer_i] 258 | elif module_def["type"] == "yolo": 259 | x, layer_loss = module[0](x, targets, img_dim) 260 | loss += layer_loss 261 | yolo_outputs.append(x) 262 | layer_outputs.append(x) 263 | yolo_outputs = to_cpu(torch.cat(yolo_outputs, 1)) 264 | return yolo_outputs if targets is None else (loss, yolo_outputs) 265 | 266 | def load_darknet_weights(self, weights_path): 267 | """Parses and loads the weights stored in 'weights_path'""" 268 | 269 | # Open the weights file 270 | with open(weights_path, "rb") as f: 271 | header = np.fromfile(f, dtype=np.int32, count=5) # First five are header values 272 | self.header_info = header # Needed to write header when saving weights 273 | self.seen = header[3] # number of images seen during training 274 | weights = np.fromfile(f, dtype=np.float32) # The rest are weights 275 | 276 | # Establish cutoff for loading backbone weights 277 | cutoff = None 278 | if "darknet53.conv.74" in weights_path: 279 | cutoff = 75 280 | 281 | ptr = 0 282 | for i, (module_def, module) in enumerate(zip(self.module_defs, self.module_list)): 283 | if i == cutoff: 284 | break 285 | if module_def["type"] == "convolutional": 286 | conv_layer = module[0] 287 | if module_def["batch_normalize"]: 288 | # Load BN bias, weights, running mean and running variance 289 | bn_layer = module[1] 290 | num_b = bn_layer.bias.numel() # Number of biases 291 | # Bias 292 | bn_b = torch.from_numpy(weights[ptr : ptr + num_b]).view_as(bn_layer.bias) 293 | bn_layer.bias.data.copy_(bn_b) 294 | ptr += num_b 295 | # Weight 296 | bn_w = torch.from_numpy(weights[ptr : ptr + num_b]).view_as(bn_layer.weight) 297 | bn_layer.weight.data.copy_(bn_w) 298 | ptr += num_b 299 | # Running Mean 300 | bn_rm = torch.from_numpy(weights[ptr : ptr + num_b]).view_as(bn_layer.running_mean) 301 | bn_layer.running_mean.data.copy_(bn_rm) 302 | ptr += num_b 303 | # Running Var 304 | bn_rv = torch.from_numpy(weights[ptr : ptr + num_b]).view_as(bn_layer.running_var) 305 | bn_layer.running_var.data.copy_(bn_rv) 306 | ptr += num_b 307 | else: 308 | # Load conv. bias 309 | num_b = conv_layer.bias.numel() 310 | conv_b = torch.from_numpy(weights[ptr : ptr + num_b]).view_as(conv_layer.bias) 311 | conv_layer.bias.data.copy_(conv_b) 312 | ptr += num_b 313 | # Load conv. weights 314 | num_w = conv_layer.weight.numel() 315 | conv_w = torch.from_numpy(weights[ptr : ptr + num_w]).view_as(conv_layer.weight) 316 | conv_layer.weight.data.copy_(conv_w) 317 | ptr += num_w 318 | 319 | def save_darknet_weights(self, path, cutoff=-1): 320 | """ 321 | @:param path - path of the new weights file 322 | @:param cutoff - save layers between 0 and cutoff (cutoff = -1 -> all are saved) 323 | """ 324 | fp = open(path, "wb") 325 | self.header_info[3] = self.seen 326 | self.header_info.tofile(fp) 327 | 328 | # Iterate through layers 329 | for i, (module_def, module) in enumerate(zip(self.module_defs[:cutoff], self.module_list[:cutoff])): 330 | if module_def["type"] == "convolutional": 331 | conv_layer = module[0] 332 | # If batch norm, load bn first 333 | if module_def["batch_normalize"]: 334 | bn_layer = module[1] 335 | bn_layer.bias.data.cpu().numpy().tofile(fp) 336 | bn_layer.weight.data.cpu().numpy().tofile(fp) 337 | bn_layer.running_mean.data.cpu().numpy().tofile(fp) 338 | bn_layer.running_var.data.cpu().numpy().tofile(fp) 339 | # Load conv bias 340 | else: 341 | conv_layer.bias.data.cpu().numpy().tofile(fp) 342 | # Load conv weights 343 | conv_layer.weight.data.cpu().numpy().tofile(fp) 344 | 345 | fp.close() 346 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | --------------------------------------------------------------------------------