├── .gitignore ├── README.md ├── classification ├── README.md ├── data │ ├── create_finetune_data.py │ ├── generate_data.py │ ├── residential_occupancy_types.json │ └── split_data.py ├── output │ ├── labels.json │ ├── labels_0.json │ ├── labels_100.json │ ├── labels_1000.json │ ├── labels_10000.json │ ├── labels_50.json │ ├── labels_500.json │ ├── preds.json │ ├── preds_0.json │ ├── preds_100.json │ ├── preds_1000.json │ ├── preds_10000.json │ ├── preds_50.json │ ├── preds_500.json │ └── result.json ├── pred_compare.py └── train.py ├── detection ├── README.md ├── __pycache__ │ └── models.cpython-36.pyc ├── assets │ ├── dog.png │ ├── giraffe.png │ ├── messi.png │ └── traffic.png ├── config │ ├── res.data │ ├── yolov3-tiny.cfg │ └── yolov3.cfg ├── data │ ├── generate_data.py │ ├── make_config.py │ ├── res.names │ └── residential_occupancy_types.json ├── detect.py ├── models.py ├── report_1.pdf ├── requirements.txt ├── test.py ├── train.py ├── utils │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-36.pyc │ │ ├── datasets.cpython-36.pyc │ │ ├── parse_config.cpython-36.pyc │ │ └── utils.cpython-36.pyc │ ├── datasets.py │ ├── parse_config.py │ └── utils.py └── visualize.py └── new_detection ├── .gitignore ├── best_practice.txt ├── config ├── res.data ├── test_config.txt └── train_config.txt ├── dataset.py ├── eval.py ├── eval_result.json ├── model.py ├── train.py └── utils.py /.gitignore: -------------------------------------------------------------------------------- 1 | detection/weights 2 | classification/weights 3 | detection/data/arcgis_config.py -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # satellite_building_detection.pytorch 2 | 3 | This repo contains two modules for detecting and classifying residential buildings based on satellite images. Each module contains 4 | python scripts for generating training images and annotations and code to perform training and evaluation. 5 | 6 | For detailed descriptions, check the README file in each module. 7 | -------------------------------------------------------------------------------- /classification/README.md: -------------------------------------------------------------------------------- 1 | # Building classification 2 | While classification is part of the detection module already, this module separately performs classification with better quality satellite images. 3 | 4 | ## Data Preparation 5 | Python script for generating training images and annotations are placed inside data/ folder. Satellite images are classified into residential vs. non-residential types. 6 | 7 | ## Model Structure 8 | This module uses a pre-trained DenseNet as the backbone model structure to perform binary classification. -------------------------------------------------------------------------------- /classification/data/create_finetune_data.py: -------------------------------------------------------------------------------- 1 | import os 2 | from shutil import copyfile 3 | 4 | sizes = [10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000] 5 | output_dir = 'wc_finetune' 6 | 7 | for size in sizes: 8 | # take as much as we could from non-residential data. If not enough, fill with residential data 9 | # output path: wc_finetune/size/residential(non_residential) 10 | res_output = output_dir + '/' + str(size) + '/train/' + 'residential' 11 | nonres_output = output_dir + '/' + str(size) + '/train/' + 'non_residential' 12 | if not os.path.exists(res_output): 13 | os.makedirs(res_output) 14 | if not os.path.exists(nonres_output): 15 | os.makedirs(nonres_output) 16 | nonres_size = size / 2 17 | nonres_count = 0 18 | for root, dirs, files in os.walk('images/train/non_residential'): 19 | for filename in files: 20 | source = root + '/' + filename 21 | target = nonres_output + '/' + filename 22 | copyfile(source, target) 23 | nonres_count += 1 24 | if nonres_count >= nonres_size: 25 | break 26 | res_size = size - nonres_count 27 | res_count = 0 28 | for root, dirs, files in os.walk('images/train/residential'): 29 | for filename in files: 30 | source = root + '/' + filename 31 | target = res_output + '/' + filename 32 | copyfile(source, target) 33 | res_count += 1 34 | if res_count >= res_size: 35 | break 36 | -------------------------------------------------------------------------------- /classification/data/generate_data.py: -------------------------------------------------------------------------------- 1 | from arcgis.gis import GIS 2 | from arcgis.features import SpatialDataFrame 3 | from arcgis.raster import ImageryLayer 4 | from arcgis.geometry import Polygon 5 | from arcgis.geometry import Geometry 6 | import sys 7 | import json 8 | import os 9 | 10 | # type of coordinate referrence system 11 | crs_id = 3857 12 | gis = GIS("https://www.arcgis.com", "YuansongFengPro", "Fys19970807!") 13 | 14 | shp_file = 'raw/bottom_part.shp' 15 | building_data = SpatialDataFrame.from_featureclass(shp_file) 16 | output_dir = './images' 17 | 18 | # naip = gis.content.search('Views', 'Imagery Layer', outside_org=True) 19 | naip = gis.content.get('3f8d2d3828f24c00ae279db4af26d566') 20 | # for layer in naip.layers: 21 | # print(layer) 22 | naip_image_layer = naip.layers[0] 23 | # naip_image_layer = apply(naip_image_layer, 'FalseColorComposite') 24 | # print(naip_image_layer.extent) 25 | 26 | # redefine occupancy type to be residential(1) and non-residential(2) 27 | with open('residential_occupancy_types.json', 'r') as f: 28 | res_types = json.load(f) 29 | 30 | image_size = 224 31 | res_idx = 0 32 | nonres_idx = 0 33 | # number of output class for each category 34 | output_num = 10000 35 | 36 | # iterate through building instances on image layer and crop down each instance 37 | for idx, bbox in enumerate(building_data.geometry): 38 | try: 39 | building_type = int(building_data['OCCUP_TYPE'][idx]) 40 | if building_type in res_types: 41 | continue 42 | # res_idx += 1 43 | # print(res_idx) 44 | # if res_idx >= output_num: 45 | # continue 46 | # output_folder = os.path.join(output_dir, 'residential') 47 | # output_filename = str(res_idx)+'.jpg' 48 | else: 49 | nonres_idx += 1 50 | if nonres_idx >= output_num: 51 | break 52 | output_folder = os.path.join(output_dir, 'non_residential') 53 | output_filename = str(nonres_idx)+'.jpg' 54 | # bbox is polygon 55 | x1_r, y1_r, x2_r, y2_r = bbox.extent 56 | pad = (x2_r-x1_r) / 4 57 | extent = {'xmin':x1_r-pad, 'ymin':y1_r-pad, 'xmax':x2_r+pad, 'ymax':y2_r+pad, 'spatialReference':crs_id} 58 | naip_image_layer.export_image( 59 | extent, 60 | size=[image_size, image_size], 61 | save_folder=output_folder, 62 | save_file=output_filename, 63 | f='image', 64 | export_format='jpg', 65 | adjust_aspect_ratio=False 66 | ) 67 | print('image outputted to %s' % (output_folder+'/'+output_filename)) 68 | if (res_idx == output_num) and (nonres_idx == output_num): 69 | break 70 | except Exception as e: 71 | print(e) 72 | continue 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /classification/data/residential_occupancy_types.json: -------------------------------------------------------------------------------- 1 | [ 2 | 1245, 3 | 1250, 4 | 1255, 5 | 1260, 6 | 1265, 7 | 1270, 8 | 1275, 9 | 1280, 10 | 1285, 11 | 1290, 12 | 1295, 13 | 1580, 14 | 1585, 15 | 1590, 16 | 1595, 17 | 1600, 18 | 1605, 19 | 1610, 20 | 1615, 21 | 1620, 22 | 1625, 23 | 1630, 24 | 2245, 25 | 2250, 26 | 2255, 27 | 2260, 28 | 2265, 29 | 2270, 30 | 2275, 31 | 2280, 32 | 2285, 33 | 2290, 34 | 2295, 35 | 2580, 36 | 2585, 37 | 2590, 38 | 2595, 39 | 2600, 40 | 2605, 41 | 2610, 42 | 2615, 43 | 2620, 44 | 2625, 45 | 2630, 46 | 3245, 47 | 3250, 48 | 3255, 49 | 3260, 50 | 3265, 51 | 3270, 52 | 3275, 53 | 3280, 54 | 3285, 55 | 3290, 56 | 3295, 57 | 4245, 58 | 4250, 59 | 4255, 60 | 4260, 61 | 4265, 62 | 4270, 63 | 4275, 64 | 4280, 65 | 4285, 66 | 4290, 67 | 4295, 68 | 5245, 69 | 5250, 70 | 5255, 71 | 5260, 72 | 5265, 73 | 5270, 74 | 5275, 75 | 5280, 76 | 5285, 77 | 5290, 78 | 5295, 79 | 5580, 80 | 5585, 81 | 5590, 82 | 5595, 83 | 5600, 84 | 5605, 85 | 5610, 86 | 5615, 87 | 5620, 88 | 5625, 89 | 5630 90 | ] -------------------------------------------------------------------------------- /classification/data/split_data.py: -------------------------------------------------------------------------------- 1 | from shutil import copyfile 2 | import random 3 | import os 4 | 5 | for label in ['residential', 'non_residential']: 6 | for finetune_size in ['500', '1000', '2000', '5000', '10000']: 7 | for root, dirs, files in os.walk('/data/feng/building-classify/wc_finetune/' + finetune_size + '/' + label): 8 | for filename in files: 9 | r = random.random() 10 | target_dir = '' 11 | if r < 0.1: 12 | target_dir = 'test' 13 | elif r < 0.2: 14 | target_dir = 'val' 15 | else: 16 | target_dir = 'train' 17 | target_filename = '/data/feng/building-classify/wc_finetune/' + finetune_size + '/' + target_dir + '/' + label + '/' + filename 18 | if not os.path.exists('/data/feng/building-classify/wc_finetune/' + finetune_size + '/' + target_dir + '/' + label + '/'): 19 | os.makedirs('/data/feng/building-classify/wc_finetune/' + finetune_size + '/' + target_dir + '/' + label + '/') 20 | source_filename = '/data/feng/building-classify/wc_finetune/' + finetune_size + '/' + label + '/' + filename 21 | copyfile(source_filename, target_filename) -------------------------------------------------------------------------------- /classification/output/labels.json: -------------------------------------------------------------------------------- 1 | [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1]] -------------------------------------------------------------------------------- /classification/output/labels_0.json: -------------------------------------------------------------------------------- 1 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] -------------------------------------------------------------------------------- /classification/output/labels_100.json: -------------------------------------------------------------------------------- 1 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] -------------------------------------------------------------------------------- /classification/output/labels_1000.json: -------------------------------------------------------------------------------- 1 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] -------------------------------------------------------------------------------- /classification/output/labels_10000.json: -------------------------------------------------------------------------------- 1 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] -------------------------------------------------------------------------------- /classification/output/labels_50.json: -------------------------------------------------------------------------------- 1 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] -------------------------------------------------------------------------------- /classification/output/labels_500.json: -------------------------------------------------------------------------------- 1 | [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] -------------------------------------------------------------------------------- /classification/pred_compare.py: -------------------------------------------------------------------------------- 1 | import json 2 | import csv 3 | 4 | with open('preds_0.json', 'r') as f: 5 | pred_0 = json.load(f) 6 | with open('preds_50.json', 'r') as f: 7 | pred_50 = json.load(f) 8 | with open('preds_100.json', 'r') as f: 9 | pred_100 = json.load(f) 10 | with open('preds_500.json', 'r') as f: 11 | pred_500 = json.load(f) 12 | with open('preds_1000.json', 'r') as f: 13 | pred_1000 = json.load(f) 14 | with open('preds_10000.json', 'r') as f: 15 | pred_10000 = json.load(f) 16 | with open('labels_0.json', 'r') as f: 17 | labels = json.load(f) 18 | 19 | 20 | with open('result.csv', 'w') as f: 21 | writer = csv.writer(f, delimiter=',') 22 | writer.writerow(['building', 'true', 'TS0', 'TS50', 'TS100', 'TS500', 'TS1000', 'TS10000']) 23 | for idx in range(len(pred_0)): 24 | l = labels[idx] 25 | writer.writerow([idx, 1-l, pred_0[idx][0], pred_50[idx][0], pred_100[idx][0], pred_500[idx][0], pred_1000[idx][0], pred_10000[idx][0]]) -------------------------------------------------------------------------------- /classification/train.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | from __future__ import division 3 | import torch 4 | import torch.nn as nn 5 | import torch.optim as optim 6 | import numpy as np 7 | import torchvision 8 | from torchvision import datasets, models, transforms 9 | import matplotlib.pyplot as plt 10 | import time 11 | import os 12 | import copy 13 | import cv2 as cv 14 | import json 15 | 16 | # Top level data directory. Here we assume the format of the directory conforms 17 | # to the ImageFolder structure 18 | data_dir = "/data/feng/wc/wc_finetune/10" 19 | 20 | # Models to choose from [resnet, alexnet, vgg, squeezenet, densenet, inception] 21 | model_name = "densenet" 22 | # Number of classes in the dataset 23 | num_classes = 2 24 | # Batch size for training (change depending on how much memory you have) 25 | batch_size = 32 26 | # Number of epochs to train for 27 | num_epochs = 50 28 | # Flag for feature extracting. When False, we finetune the whole model, 29 | # when True we only update the reshaped layer params 30 | feature_extract = False 31 | 32 | def train_model(model, dataloaders, criterion, optimizer, num_epochs=25, is_inception=False): 33 | since = time.time() 34 | 35 | val_acc_history = [] 36 | 37 | best_model_wts = copy.deepcopy(model.state_dict()) 38 | best_acc = 0.0 39 | # output_yet = False 40 | for epoch in range(num_epochs): 41 | print('Epoch {}/{}'.format(epoch, num_epochs - 1)) 42 | print('-' * 10) 43 | 44 | # Each epoch has a training and validation phase 45 | for phase in ['val']: 46 | if phase == 'train': 47 | model.train() # Set model to training mode 48 | else: 49 | model.eval() # Set model to evaluate mode 50 | 51 | running_loss = 0.0 52 | running_corrects = 0 53 | true_negatives = 0.0 54 | true_positives = 0.0 55 | false_negatives = 0.0 56 | false_positives = 0.0 57 | output_idx = 0 58 | all_preds = [] 59 | all_labels = [] 60 | # Iterate over data. 61 | for inputs, labels in dataloaders[phase]: 62 | inputs = inputs.to(device) 63 | labels = labels.to(device) 64 | 65 | # zero the parameter gradients 66 | optimizer.zero_grad() 67 | 68 | # forward 69 | # track history if only in train 70 | with torch.set_grad_enabled(phase == 'train'): 71 | # Get model outputs and calculate loss 72 | # Special case for inception because in training it has an auxiliary output. In train 73 | # mode we calculate the loss by summing the final output and the auxiliary output 74 | # but in testing we only consider the final output. 75 | if is_inception and phase == 'train': 76 | # From https://discuss.pytorch.org/t/how-to-optimize-inception-model-with-auxiliary-classifiers/7958 77 | outputs, aux_outputs = model(inputs) 78 | loss1 = criterion(outputs, labels) 79 | loss2 = criterion(aux_outputs, labels) 80 | loss = loss1 + 0.4*loss2 81 | else: 82 | outputs = model(inputs) 83 | loss = criterion(outputs, labels) 84 | 85 | _, preds = torch.max(outputs, 1) 86 | 87 | # backward + optimize only if in training phase 88 | if phase == 'train': 89 | loss.backward() 90 | optimizer.step() 91 | 92 | # statistics 93 | running_loss += loss.item() * inputs.size(0) 94 | running_corrects += torch.sum(preds == labels.data) 95 | TP = 0 # label 0, predict 0 96 | FN = 0 # label 0, predict 1 97 | TN = 0 # label 1, predict 1 98 | FP = 0 # label 1, predict 0 99 | confusion_vector = preds.cpu().numpy() / labels.data.cpu().numpy() 100 | # Element-wise division of the 2 tensors returns a new tensor which holds a 101 | # unique value for each case: 102 | # 1 where prediction and truth are 1 (True Negative) 103 | # inf where prediction is 1 and truth is 0 (False Negative) 104 | # nan where prediction and truth are 0 (True Positive) 105 | # 0 where prediction is 0 and truth is 1 (False Positive) 106 | # print(preds) 107 | # print(labels.data) 108 | # print(confusion_vector) 109 | true_negatives += np.sum(confusion_vector == 1) 110 | false_negatives += np.sum(confusion_vector == float('inf')) 111 | true_positives += np.sum(np.isnan(confusion_vector)) 112 | false_positives += np.sum(confusion_vector == 0) 113 | 114 | 115 | # store examples 116 | tn = confusion_vector == 1 117 | fn = confusion_vector == float('inf') 118 | tp = np.isnan(confusion_vector) 119 | fp = confusion_vector == 0 120 | # print(labels) 121 | for i in range(len(tn)): 122 | if tn[i]: 123 | output_dir = './res_correct/' 124 | elif fn[i]: 125 | output_dir = './nonres_wrong/' 126 | elif tp[i]: 127 | output_dir = './nonres_correct/' 128 | else: 129 | output_dir = './res_wrong/' 130 | image = inputs[i].cpu().numpy() 131 | image = np.moveaxis(image, 0, -1) 132 | image = image - np.min(image) 133 | image = image / np.max(image) 134 | image = np.uint8(255 * image) 135 | cv.imwrite(output_dir + str(output_idx) + '.jpg', image) 136 | output_idx += 1 137 | # output_yet = True 138 | # store all predicted accuracies 139 | outputs = torch.nn.functional.softmax(outputs) 140 | all_preds.extend(outputs.cpu().numpy().tolist()) 141 | all_labels.extend(labels.data.cpu().numpy().tolist()) 142 | if not epoch == 0: 143 | continue 144 | # finish iterating through all data 145 | with open('preds_0.json', 'w') as f: 146 | json.dump(all_preds, f) 147 | with open('labels_0.json', 'w') as f: 148 | json.dump(all_labels, f) 149 | 150 | 151 | 152 | 153 | TPR = true_positives / (true_positives + false_negatives) 154 | TNR = true_negatives / (true_negatives + false_positives) 155 | epoch_loss = running_loss / len(dataloaders[phase].dataset) 156 | epoch_acc = running_corrects.double() / len(dataloaders[phase].dataset) 157 | 158 | print('{} Loss: {:.4f} Acc: {:.4f}'.format(phase, epoch_loss, epoch_acc)) 159 | print('{} TPR: {:.4f} TNR: {:.4f}'.format(phase, TPR, TNR)) 160 | 161 | # deep copy the model 162 | if phase == 'val' and epoch_acc > best_acc: 163 | best_acc = epoch_acc 164 | best_model_wts = copy.deepcopy(model.state_dict()) 165 | # https://pytorch.org/tutorials/beginner/saving_loading_models.html#saving-loading-model-for-inference 166 | # torch.save(model.state_dict(), "%s/10_best.weights" % ('checkpoints')) 167 | if phase == 'val': 168 | val_acc_history.append(epoch_acc) 169 | 170 | print() 171 | 172 | time_elapsed = time.time() - since 173 | print('Training complete in {:.0f}m {:.0f}s'.format(time_elapsed // 60, time_elapsed % 60)) 174 | print('Best val Acc: {:4f}'.format(best_acc)) 175 | 176 | # load best model weights 177 | model.load_state_dict(best_model_wts) 178 | return model, val_acc_history 179 | 180 | def set_parameter_requires_grad(model, feature_extracting): 181 | if feature_extracting: 182 | for param in model.parameters(): 183 | param.requires_grad = False 184 | 185 | def initialize_model(model_name, num_classes, feature_extract, use_pretrained=True): 186 | # Initialize these variables which will be set in this if statement. Each of these 187 | # variables is model specific. 188 | model_ft = None 189 | input_size = 0 190 | if model_name == "densenet": 191 | """ Densenet 192 | """ 193 | model_ft = models.densenet121(pretrained=use_pretrained) 194 | set_parameter_requires_grad(model_ft, feature_extract) 195 | num_ftrs = model_ft.classifier.in_features 196 | model_ft.classifier = nn.Linear(num_ftrs, num_classes) 197 | input_size = 224 198 | # Load Pre-trained model on fmow dataset 199 | model_ft.load_state_dict(torch.load('checkpoints/best_fmow.weights')) 200 | 201 | else: 202 | print("Invalid model name, exiting...") 203 | exit() 204 | 205 | return model_ft, input_size 206 | 207 | # Initialize the model for this run 208 | model_ft, input_size = initialize_model(model_name, num_classes, feature_extract, use_pretrained=True) 209 | 210 | # Data augmentation and normalization for training 211 | # Just normalization for validation 212 | data_transforms = { 213 | 'train': transforms.Compose([ 214 | transforms.RandomResizedCrop(input_size), 215 | transforms.RandomHorizontalFlip(), 216 | transforms.ToTensor(), 217 | transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) 218 | ]), 219 | 'val': transforms.Compose([ 220 | transforms.Resize(input_size), 221 | transforms.CenterCrop(input_size), 222 | transforms.ToTensor(), 223 | transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) 224 | ]), 225 | } 226 | 227 | # Create training and validation datasets 228 | image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x), data_transforms[x]) for x in ['train', 'val']} 229 | # Create training and validation dataloaders 230 | dataloaders_dict = {x: torch.utils.data.DataLoader(image_datasets[x], batch_size=batch_size, shuffle=False, num_workers=4) for x in ['train', 'val']} 231 | 232 | # Detect if we have a GPU available 233 | device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") 234 | 235 | # Send the model to GPU 236 | model_ft = model_ft.to(device) 237 | 238 | # Gather the parameters to be optimized/updated in this run. If we are 239 | # finetuning we will be updating all parameters. However, if we are 240 | # doing feature extract method, we will only update the parameters 241 | # that we have just initialized, i.e. the parameters with requires_grad 242 | # is True. 243 | params_to_update = model_ft.parameters() 244 | 245 | # Observe that all parameters are being optimized 246 | optimizer_ft = optim.SGD(params_to_update, lr=0.001, momentum=0.9) 247 | 248 | # Setup the loss fxn 249 | criterion = nn.CrossEntropyLoss() 250 | 251 | # Train and evaluate 252 | model_ft, hist = train_model(model_ft, dataloaders_dict, criterion, optimizer_ft, num_epochs=num_epochs, is_inception=(model_name=="inception")) 253 | -------------------------------------------------------------------------------- /detection/README.md: -------------------------------------------------------------------------------- 1 | # Building detection 2 | Detect buildings from satellite images and perform classification. Region proposals and classification are done in one scan following the model structure of YOLO v3. 3 | 4 | ## Data Preparation 5 | Images containing multiple buildings along with annotations are generated with a python script inside data folder. Note that the current workflow requires a Pro account in ArcGis and a shapefile for the interested region. Following steps are taken: 6 | 1. Log into ArcGis 7 | 2. Access the satellite image layer on ArcGis and generate image tiles of the interested region 8 | 3. For each image tile, iterate through all building features in the shapefile and create an annotation file 9 | 10 | 11 | ## Credit 12 | ``` 13 | @article{yolov3, 14 | title={YOLOv3: An Incremental Improvement}, 15 | author={Redmon, Joseph and Farhadi, Ali}, 16 | journal = {arXiv}, 17 | year={2018} 18 | } 19 | ``` 20 | -------------------------------------------------------------------------------- /detection/__pycache__/models.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yfeng997/satellite_building_detection.pytorch/e73e8924757abc4ec950d488841df6e48fe4e951/detection/__pycache__/models.cpython-36.pyc -------------------------------------------------------------------------------- /detection/assets/dog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yfeng997/satellite_building_detection.pytorch/e73e8924757abc4ec950d488841df6e48fe4e951/detection/assets/dog.png -------------------------------------------------------------------------------- /detection/assets/giraffe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yfeng997/satellite_building_detection.pytorch/e73e8924757abc4ec950d488841df6e48fe4e951/detection/assets/giraffe.png -------------------------------------------------------------------------------- /detection/assets/messi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yfeng997/satellite_building_detection.pytorch/e73e8924757abc4ec950d488841df6e48fe4e951/detection/assets/messi.png -------------------------------------------------------------------------------- /detection/assets/traffic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yfeng997/satellite_building_detection.pytorch/e73e8924757abc4ec950d488841df6e48fe4e951/detection/assets/traffic.png -------------------------------------------------------------------------------- /detection/config/res.data: -------------------------------------------------------------------------------- 1 | classes= 2 2 | train=/data/feng/building/config/train_config.txt 3 | test=/data/feng/building/config/test_config.txt 4 | names=data/res.names 5 | backup=backup/ 6 | -------------------------------------------------------------------------------- /detection/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=255 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=80 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=255 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=80 202 | num=6 203 | jitter=.3 204 | ignore_thresh = .7 205 | truth_thresh = 1 206 | random=1 207 | -------------------------------------------------------------------------------- /detection/config/yolov3.cfg: -------------------------------------------------------------------------------- 1 | [net] 2 | # Testing 3 | #batch=1 4 | #subdivisions=1 5 | # Training 6 | batch=16 7 | subdivisions=1 8 | width=224 9 | height=224 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=21 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=2 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=21 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=2 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=21 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=2 784 | num=9 785 | jitter=.3 786 | ignore_thresh = .7 787 | truth_thresh = 1 788 | random=1 789 | -------------------------------------------------------------------------------- /detection/data/generate_data.py: -------------------------------------------------------------------------------- 1 | from arcgis.gis import GIS 2 | from arcgis.features import SpatialDataFrame 3 | from arcgis.raster import ImageryLayer 4 | from arcgis.geometry import Polygon 5 | from arcgis.geometry import Geometry 6 | import sys 7 | import json 8 | import arcgis_config 9 | 10 | # type of coordinate referrence system 11 | crs_id = 3857 12 | gis = GIS("https://www.arcgis.com", arcgis_config.username, arcgis_config.password) 13 | 14 | shp_file = 'raw/bottom_part.shp' 15 | building_data = SpatialDataFrame.from_featureclass(shp_file) 16 | # print(type(building_data.geometry)) 17 | # print(df.dtypes) 18 | # print(df.shape) 19 | 20 | # naip = gis.content.search('Views', 'Imagery Layer', outside_org=True) 21 | naip = gis.content.get('3f8d2d3828f24c00ae279db4af26d566') 22 | # for layer in naip.layers: 23 | # print(layer) 24 | naip_image_layer = naip.layers[0] 25 | # naip_image_layer = apply(naip_image_layer, 'FalseColorComposite') 26 | # print(naip_image_layer.extent) 27 | 28 | # redefine occupancy type to be residential(1) and non-residential(2) 29 | with open('residential_occupancy_types.json', 'r') as f: 30 | res_types = json.load(f) 31 | 32 | 33 | # find the min/max of x and y coordinates of all buildings. 34 | # min_x = -8791910.9147 35 | # min_y = 4234675.8780 36 | # max_x = -8711883.4966 37 | # max_y = 4311092.4135 38 | min_x = -8784796.6706 39 | min_y = 4242405.9333 40 | max_x = -8752365.2401 41 | max_y = 4261174.7474 42 | # we operate on 200 level 43 | tile_size = 200 44 | image_size = 224 45 | x_num_tile = int((max_x - min_x) / tile_size) + 1 46 | y_num_tile = int((max_y - min_y) / tile_size) + 1 47 | 48 | def overlap(a, b): 49 | x1, y1, x2, y2 = a 50 | def point_in(p, box): 51 | m1, n1, m2, n2 = box 52 | x, y = p 53 | if x >= m1 and x <= m2 and y >= n1 and y <= n2: 54 | return True 55 | return False 56 | return (point_in((x1, y1), b)) or (point_in((x2, y1), b)) or (point_in((x2, y2), b)) or (point_in((x1, y2), b)) 57 | 58 | # iterate through image tiles on naip_image_layer starting from bottom row 59 | for y_idx in range(y_num_tile): 60 | for x_idx in range(x_num_tile): 61 | image_name = str(y_idx*x_num_tile + x_idx) 62 | x_start = min_x + x_idx * tile_size 63 | y_start = min_y + y_idx * tile_size 64 | 65 | # export annotations for buildings in the image 66 | tile_image_geometry = Geometry({ 67 | "rings" : [[[x_start,y_start],[x_start+tile_size,y_start],[x_start+tile_size,y_start+tile_size],[x_start,y_start+tile_size]]], 68 | "spatialReference" : {"wkid" : crs_id} 69 | }) 70 | annotations = [] 71 | for idx, bbox in enumerate(building_data.geometry): 72 | # bbox is polygon 73 | bbox_extent = bbox.extent 74 | tile_extent = tile_image_geometry.extent 75 | try: 76 | # if bbox overlaps with tile image extent, record the building bbox 77 | if overlap(bbox_extent, tile_extent): 78 | # bbox contains normalized [xywh] 79 | x1_r, y1_r, x2_r, y2_r = bbox_extent 80 | # clipping 81 | x1 = max(x_start, x1_r) 82 | y1 = max(y_start, y1_r) 83 | x2 = min(x2_r, x_start+tile_size) 84 | y2 = min(y2_r, y_start+tile_size) 85 | x = (x1-x_start) / tile_size 86 | y = (tile_size+y_start-y2) / tile_size 87 | w = (x2-x1) / tile_size 88 | h = (y2-y1) / tile_size 89 | # keep big building instance 90 | if not ((x2_r - x1_r) * (y2_r - y1_r)) >= (0.3 * tile_size * tile_size): 91 | # else, drop significantly clipped building instances 92 | if ((x2 - x1) * (y2 - y1)) <= (0.5 * ((x2_r - x1_r) * (y2_r - y1_r))): 93 | continue 94 | assert x >= 0 and x <= 1 95 | assert y >= 0 and y <= 1 96 | assert w >= 0 and w <= 1 97 | assert h >= 0 and h <= 1 98 | building_type = int(building_data['OCCUP_TYPE'][idx]) 99 | # print(building_type) 100 | # 0 is residential and 1 is non-residential 101 | building_class = 0 if building_type in res_types else 1 102 | annotations.append({ 103 | 'bbox': [x, y, w, h], 104 | 'class': building_class 105 | }) 106 | except: 107 | continue 108 | if len(annotations) == 0: 109 | continue 110 | annotation_output = './tmp_annotations/'+image_name+'.json' 111 | with open(annotation_output, 'w') as f: 112 | json.dump(annotations, f, indent=4) 113 | print('annotation outputted to %s' % annotation_output) 114 | 115 | # export the tile image 116 | extent = {'xmin':x_start, 'ymin':y_start, 'xmax':x_start + tile_size, 'ymax':y_start + tile_size, 'spatialReference':crs_id} 117 | naip_image_layer.export_image( 118 | extent, 119 | size=[image_size, image_size], 120 | save_folder='./tmp_images', 121 | save_file=image_name+'.jpg', 122 | f='image', 123 | export_format='jpg', 124 | adjust_aspect_ratio=False 125 | ) 126 | print('image outputted to %s' % ('./images/'+image_name+'.jpg')) 127 | -------------------------------------------------------------------------------- /detection/data/make_config.py: -------------------------------------------------------------------------------- 1 | import os 2 | import random 3 | 4 | train_config_file = './config/train_config.txt' 5 | test_config_file = './config/test_config.txt' 6 | images_dir = '/data/feng/building/images' 7 | 8 | f = open(train_config_file, 'w') 9 | t = open(test_config_file, 'w') 10 | 11 | for root, dirs, files in os.walk(images_dir): 12 | for filename in files: 13 | if filename.endswith('.jpg'): 14 | if random.random() < 0.05: 15 | # write as test data 16 | t.write(os.path.join(root, filename)+'\n') 17 | else: 18 | # write as train data 19 | f.write(os.path.join(root, filename)+'\n') 20 | 21 | f.close() 22 | t.close() -------------------------------------------------------------------------------- /detection/data/res.names: -------------------------------------------------------------------------------- 1 | residential 2 | non_residential 3 | -------------------------------------------------------------------------------- /detection/data/residential_occupancy_types.json: -------------------------------------------------------------------------------- 1 | [ 2 | 1245, 3 | 1250, 4 | 1255, 5 | 1260, 6 | 1265, 7 | 1270, 8 | 1275, 9 | 1280, 10 | 1285, 11 | 1290, 12 | 1295, 13 | 1580, 14 | 1585, 15 | 1590, 16 | 1595, 17 | 1600, 18 | 1605, 19 | 1610, 20 | 1615, 21 | 1620, 22 | 1625, 23 | 1630, 24 | 2245, 25 | 2250, 26 | 2255, 27 | 2260, 28 | 2265, 29 | 2270, 30 | 2275, 31 | 2280, 32 | 2285, 33 | 2290, 34 | 2295, 35 | 2580, 36 | 2585, 37 | 2590, 38 | 2595, 39 | 2600, 40 | 2605, 41 | 2610, 42 | 2615, 43 | 2620, 44 | 2625, 45 | 2630, 46 | 3245, 47 | 3250, 48 | 3255, 49 | 3260, 50 | 3265, 51 | 3270, 52 | 3275, 53 | 3280, 54 | 3285, 55 | 3290, 56 | 3295, 57 | 4245, 58 | 4250, 59 | 4255, 60 | 4260, 61 | 4265, 62 | 4270, 63 | 4275, 64 | 4280, 65 | 4285, 66 | 4290, 67 | 4295, 68 | 5245, 69 | 5250, 70 | 5255, 71 | 5260, 72 | 5265, 73 | 5270, 74 | 5275, 75 | 5280, 76 | 5285, 77 | 5290, 78 | 5295, 79 | 5580, 80 | 5585, 81 | 5590, 82 | 5595, 83 | 5600, 84 | 5605, 85 | 5610, 86 | 5615, 87 | 5620, 88 | 5625, 89 | 5630 90 | ] -------------------------------------------------------------------------------- /detection/detect.py: -------------------------------------------------------------------------------- 1 | from __future__ import division 2 | import matplotlib 3 | matplotlib.use('Agg') 4 | from models import * 5 | from utils.utils import * 6 | from utils.datasets import * 7 | 8 | import os 9 | import sys 10 | import time 11 | import datetime 12 | import argparse 13 | import json 14 | 15 | import torch 16 | from torch.utils.data import DataLoader 17 | from torchvision import datasets 18 | from torch.autograd import Variable 19 | import torchvision.transforms as transforms 20 | # from torchvision.datasets import ImageFolder 21 | 22 | import matplotlib.pyplot as plt 23 | import matplotlib.patches as patches 24 | from matplotlib.ticker import NullLocator 25 | 26 | parser = argparse.ArgumentParser() 27 | parser.add_argument('--image_folder', type=str, default='data/compose', help='path to dataset') 28 | parser.add_argument('--config_path', type=str, default='config/yolov3.cfg', help='path to model config file') 29 | parser.add_argument('--weights_path', type=str, default='checkpoints/90.weights', help='path to weights file') 30 | parser.add_argument('--class_path', type=str, default='data/res.names', help='path to class label file') 31 | parser.add_argument('--conf_thres', type=float, default=0.8, help='object confidence threshold') 32 | parser.add_argument('--nms_thres', type=float, default=0.4, help='iou thresshold for non-maximum suppression') 33 | parser.add_argument('--batch_size', type=int, default=1, help='size of the batches') 34 | parser.add_argument('--n_cpu', type=int, default=8, help='number of cpu threads to use during batch generation') 35 | parser.add_argument('--img_size', type=int, default=224, help='size of each image dimension') 36 | parser.add_argument('--use_cuda', type=bool, default=True, help='whether to use cuda if available') 37 | opt = parser.parse_args() 38 | print(opt) 39 | 40 | cuda = torch.cuda.is_available() and opt.use_cuda 41 | 42 | os.makedirs('output_t', exist_ok=True) 43 | 44 | # Set up model 45 | model = Darknet(opt.config_path, img_size=opt.img_size) 46 | model.load_state_dict(torch.load(opt.weights_path)) 47 | 48 | if cuda: 49 | model.cuda() 50 | 51 | model.eval() # Set in evaluation mode 52 | 53 | 54 | # Note: ImageFolder is a customized version under utils.datasets.ImageFolder 55 | # instead of loading image with its label, this ImageFolder loads the image path and the image 56 | 57 | dataloader = DataLoader( 58 | ImageFolder( 59 | opt.image_folder, 60 | img_size=opt.img_size 61 | ), 62 | batch_size=opt.batch_size, 63 | shuffle=False, 64 | num_workers=opt.n_cpu 65 | ) 66 | 67 | classes = load_classes(opt.class_path) # Extracts class labels from file 68 | 69 | Tensor = torch.cuda.FloatTensor if cuda else torch.FloatTensor 70 | 71 | imgs = [] # Stores image paths 72 | img_detections = [] # Stores detections for each image index 73 | 74 | print ('\nPerforming object detection:') 75 | prev_time = time.time() 76 | for batch_i, (img_paths, input_imgs) in enumerate(dataloader): 77 | # Configure input 78 | input_imgs = Variable(input_imgs.type(Tensor)) 79 | 80 | # Get detections 81 | with torch.no_grad(): 82 | detections = model(input_imgs) 83 | detections = non_max_suppression(detections, 80, opt.conf_thres, opt.nms_thres) 84 | 85 | 86 | # Log progress 87 | current_time = time.time() 88 | inference_time = datetime.timedelta(seconds=current_time - prev_time) 89 | prev_time = current_time 90 | print ('\t+ Batch %d, Inference Time: %s' % (batch_i, inference_time)) 91 | 92 | # Save image and detections 93 | imgs.extend(img_paths) 94 | img_detections.extend(detections) 95 | 96 | # Bounding-box colors 97 | cmap = plt.get_cmap('tab20b') 98 | colors = [cmap(i) for i in np.linspace(0, 1, 20)] 99 | bbox_colors = random.sample(colors, 2) 100 | 101 | print ('\nSaving images:') 102 | # Iterate through images and save plot of detections 103 | for img_i, (path, detections) in enumerate(zip(imgs, img_detections)): 104 | 105 | print ("(%d) Image: '%s'" % (img_i, path)) 106 | 107 | # Create plot 108 | img = np.array(Image.open(path)) 109 | plt.figure() 110 | fig, ax = plt.subplots(1) 111 | ax.imshow(img) 112 | 113 | # create output stats 114 | stat = [] 115 | 116 | # The amount of padding that was added 117 | pad_x = max(img.shape[0] - img.shape[1], 0) * (opt.img_size / max(img.shape)) 118 | pad_y = max(img.shape[1] - img.shape[0], 0) * (opt.img_size / max(img.shape)) 119 | # Image height and width after padding is removed 120 | unpad_h = opt.img_size - pad_y 121 | unpad_w = opt.img_size - pad_x 122 | 123 | # Draw bounding boxes and labels of detections 124 | if detections is not None: 125 | unique_labels = detections[:, -1].cpu().unique() 126 | n_cls_preds = len(unique_labels) 127 | # bbox_colors = random.sample(colors, n_cls_preds) 128 | for x1, y1, x2, y2, conf, cls_conf, cls_pred in detections: 129 | print(cls_pred) 130 | print ('\t+ Label: %s, Conf: %.5f' % (classes[int(cls_pred)], cls_conf.item())) 131 | 132 | # Rescale coordinates to original dimensions 133 | box_h = ((y2 - y1) / unpad_h) * img.shape[0] 134 | box_w = ((x2 - x1) / unpad_w) * img.shape[1] 135 | y1 = ((y1 - pad_y // 2) / unpad_h) * img.shape[0] 136 | x1 = ((x1 - pad_x // 2) / unpad_w) * img.shape[1] 137 | 138 | color = bbox_colors[int(np.where(unique_labels == int(cls_pred))[0])] 139 | # Create a Rectangle patch 140 | bbox = patches.Rectangle((x1, y1), box_w, box_h, linewidth=2, 141 | edgecolor=color, 142 | facecolor='none') 143 | # Add the bbox to the plot 144 | ax.add_patch(bbox) 145 | # Add label 146 | plt.text(x1, y1, s=classes[int(cls_pred)], color='white', verticalalignment='top', 147 | bbox={'color': color, 'pad': 0}) 148 | # Add to stats 149 | stat.append({ 150 | 'x1': x1.item(), 151 | 'y1': y1.item(), 152 | 'w': box_w.item(), 153 | 'h': box_h.item(), 154 | 'pred_class': classes[int(cls_pred)], 155 | 'pred_conf': cls_conf.item() 156 | }) 157 | 158 | # Save generated image with detections 159 | plt.axis('off') 160 | plt.gca().xaxis.set_major_locator(NullLocator()) 161 | plt.gca().yaxis.set_major_locator(NullLocator()) 162 | plt.savefig('output_t/%d.png' % (img_i), bbox_inches='tight', pad_inches=0.0) 163 | plt.close() 164 | 165 | # Save stored stats 166 | # print(stat) 167 | # with open('output/%d.json' % (img_i), 'w') as f: 168 | # json.dump(stat, f, indent=4) 169 | 170 | -------------------------------------------------------------------------------- /detection/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 PIL import Image 10 | 11 | from utils.parse_config import * 12 | from utils.utils import build_targets 13 | from collections import defaultdict 14 | 15 | import matplotlib.pyplot as plt 16 | import matplotlib.patches as patches 17 | 18 | 19 | def create_modules(module_defs): 20 | """ 21 | Constructs module list of layer blocks from module configuration in module_defs 22 | """ 23 | hyperparams = module_defs.pop(0) 24 | output_filters = [int(hyperparams["channels"])] 25 | module_list = nn.ModuleList() 26 | for i, module_def in enumerate(module_defs): 27 | modules = nn.Sequential() 28 | 29 | if module_def["type"] == "convolutional": 30 | bn = int(module_def["batch_normalize"]) 31 | filters = int(module_def["filters"]) 32 | kernel_size = int(module_def["size"]) 33 | pad = (kernel_size - 1) // 2 if int(module_def["pad"]) else 0 34 | modules.add_module( 35 | "conv_%d" % i, 36 | nn.Conv2d( 37 | in_channels=output_filters[-1], 38 | out_channels=filters, 39 | kernel_size=kernel_size, 40 | stride=int(module_def["stride"]), 41 | padding=pad, 42 | bias=not bn, 43 | ), 44 | ) 45 | if bn: 46 | modules.add_module("batch_norm_%d" % i, nn.BatchNorm2d(filters)) 47 | if module_def["activation"] == "leaky": 48 | modules.add_module("leaky_%d" % i, nn.LeakyReLU(0.1)) 49 | 50 | elif module_def["type"] == "maxpool": 51 | kernel_size = int(module_def["size"]) 52 | stride = int(module_def["stride"]) 53 | if kernel_size == 2 and stride == 1: 54 | padding = nn.ZeroPad2d((0, 1, 0, 1)) 55 | modules.add_module("_debug_padding_%d" % i, padding) 56 | maxpool = nn.MaxPool2d( 57 | kernel_size=int(module_def["size"]), 58 | stride=int(module_def["stride"]), 59 | padding=int((kernel_size - 1) // 2), 60 | ) 61 | modules.add_module("maxpool_%d" % i, maxpool) 62 | 63 | elif module_def["type"] == "upsample": 64 | upsample = nn.Upsample(scale_factor=int(module_def["stride"]), mode="nearest") 65 | modules.add_module("upsample_%d" % i, upsample) 66 | 67 | elif module_def["type"] == "route": 68 | layers = [int(x) for x in module_def["layers"].split(",")] 69 | filters = sum([output_filters[layer_i] for layer_i in layers]) 70 | modules.add_module("route_%d" % i, EmptyLayer()) 71 | 72 | elif module_def["type"] == "shortcut": 73 | filters = output_filters[int(module_def["from"])] 74 | modules.add_module("shortcut_%d" % i, EmptyLayer()) 75 | 76 | elif module_def["type"] == "yolo": 77 | anchor_idxs = [int(x) for x in module_def["mask"].split(",")] 78 | # Extract anchors 79 | anchors = [int(x) for x in module_def["anchors"].split(",")] 80 | anchors = [(anchors[i], anchors[i + 1]) for i in range(0, len(anchors), 2)] 81 | anchors = [anchors[i] for i in anchor_idxs] 82 | num_classes = int(module_def["classes"]) 83 | img_height = int(hyperparams["height"]) 84 | # Define detection layer 85 | yolo_layer = YOLOLayer(anchors, num_classes, img_height) 86 | modules.add_module("yolo_%d" % i, yolo_layer) 87 | # Register module list and number of output filters 88 | module_list.append(modules) 89 | output_filters.append(filters) 90 | 91 | return hyperparams, module_list 92 | 93 | 94 | class EmptyLayer(nn.Module): 95 | """Placeholder for 'route' and 'shortcut' layers""" 96 | 97 | def __init__(self): 98 | super(EmptyLayer, self).__init__() 99 | 100 | 101 | class YOLOLayer(nn.Module): 102 | """Detection layer""" 103 | 104 | def __init__(self, anchors, num_classes, img_dim): 105 | super(YOLOLayer, self).__init__() 106 | self.anchors = anchors 107 | self.num_anchors = len(anchors) 108 | self.num_classes = num_classes 109 | self.bbox_attrs = 5 + num_classes 110 | self.image_dim = img_dim 111 | self.ignore_thres = 0.5 112 | self.lambda_coord = 1 113 | 114 | self.mse_loss = nn.MSELoss(size_average=True) # Coordinate loss 115 | self.bce_loss = nn.BCELoss(size_average=True) # Confidence loss 116 | self.ce_loss = nn.CrossEntropyLoss() # Class loss 117 | 118 | def forward(self, x, targets=None): 119 | nA = self.num_anchors 120 | nB = x.size(0) 121 | nG = x.size(2) 122 | stride = self.image_dim / nG 123 | 124 | # Tensors for cuda support 125 | FloatTensor = torch.cuda.FloatTensor if x.is_cuda else torch.FloatTensor 126 | LongTensor = torch.cuda.LongTensor if x.is_cuda else torch.LongTensor 127 | ByteTensor = torch.cuda.ByteTensor if x.is_cuda else torch.ByteTensor 128 | prediction = x.view(nB, nA, self.bbox_attrs, nG, nG).permute(0, 1, 3, 4, 2).contiguous() 129 | 130 | # Get outputs 131 | x = torch.sigmoid(prediction[..., 0]) # Center x 132 | y = torch.sigmoid(prediction[..., 1]) # Center y 133 | w = prediction[..., 2] # Width 134 | h = prediction[..., 3] # Height 135 | pred_conf = torch.sigmoid(prediction[..., 4]) # Conf 136 | pred_cls = torch.sigmoid(prediction[..., 5:]) # Cls pred. 137 | 138 | # Calculate offsets for each grid 139 | grid_x = torch.arange(nG).repeat(nG, 1).view([1, 1, nG, nG]).type(FloatTensor) 140 | grid_y = torch.arange(nG).repeat(nG, 1).t().view([1, 1, nG, nG]).type(FloatTensor) 141 | scaled_anchors = FloatTensor([(a_w / stride, a_h / stride) for a_w, a_h in self.anchors]) 142 | anchor_w = scaled_anchors[:, 0:1].view((1, nA, 1, 1)) 143 | anchor_h = scaled_anchors[:, 1:2].view((1, nA, 1, 1)) 144 | 145 | # Add offset and scale with anchors 146 | pred_boxes = FloatTensor(prediction[..., :4].shape) 147 | pred_boxes[..., 0] = x.data + grid_x 148 | pred_boxes[..., 1] = y.data + grid_y 149 | pred_boxes[..., 2] = torch.exp(w.data) * anchor_w 150 | pred_boxes[..., 3] = torch.exp(h.data) * anchor_h 151 | 152 | # Training 153 | if targets is not None: 154 | 155 | if x.is_cuda: 156 | self.mse_loss = self.mse_loss.cuda() 157 | self.bce_loss = self.bce_loss.cuda() 158 | self.ce_loss = self.ce_loss.cuda() 159 | 160 | nGT, nCorrect, mask, conf_mask, tx, ty, tw, th, tconf, tcls = build_targets( 161 | pred_boxes=pred_boxes.cpu().data, 162 | pred_conf=pred_conf.cpu().data, 163 | pred_cls=pred_cls.cpu().data, 164 | target=targets.cpu().data, 165 | anchors=scaled_anchors.cpu().data, 166 | num_anchors=nA, 167 | num_classes=self.num_classes, 168 | grid_size=nG, 169 | ignore_thres=self.ignore_thres, 170 | img_dim=self.image_dim, 171 | ) 172 | 173 | nProposals = int((pred_conf > 0.5).sum().item()) 174 | recall = float(nCorrect / nGT) if nGT else 1 175 | if nProposals == 0: 176 | nProposals = 1 177 | precision = float(nCorrect / nProposals) 178 | 179 | # Handle masks 180 | mask = Variable(mask.type(ByteTensor)) 181 | conf_mask = Variable(conf_mask.type(ByteTensor)) 182 | 183 | # Handle target variables 184 | tx = Variable(tx.type(FloatTensor), requires_grad=False) 185 | ty = Variable(ty.type(FloatTensor), requires_grad=False) 186 | tw = Variable(tw.type(FloatTensor), requires_grad=False) 187 | th = Variable(th.type(FloatTensor), requires_grad=False) 188 | tconf = Variable(tconf.type(FloatTensor), requires_grad=False) 189 | tcls = Variable(tcls.type(LongTensor), requires_grad=False) 190 | 191 | # Get conf mask where gt and where there is no gt 192 | conf_mask_true = mask 193 | conf_mask_false = conf_mask - mask 194 | 195 | # Mask outputs to ignore non-existing objects 196 | loss_x = self.mse_loss(x[mask], tx[mask]) 197 | loss_y = self.mse_loss(y[mask], ty[mask]) 198 | loss_w = self.mse_loss(w[mask], tw[mask]) 199 | loss_h = self.mse_loss(h[mask], th[mask]) 200 | loss_conf = self.bce_loss(pred_conf[conf_mask_false], tconf[conf_mask_false]) + self.bce_loss( 201 | pred_conf[conf_mask_true], tconf[conf_mask_true] 202 | ) 203 | loss_cls = (1 / nB) * self.ce_loss(pred_cls[mask], torch.argmax(tcls[mask], 1)) 204 | loss = loss_x + loss_y + loss_w + loss_h + loss_conf + loss_cls 205 | 206 | return ( 207 | loss, 208 | loss_x.item(), 209 | loss_y.item(), 210 | loss_w.item(), 211 | loss_h.item(), 212 | loss_conf.item(), 213 | loss_cls.item(), 214 | recall, 215 | precision, 216 | ) 217 | 218 | else: 219 | # If not in training phase return predictions 220 | output = torch.cat( 221 | ( 222 | pred_boxes.view(nB, -1, 4) * stride, 223 | pred_conf.view(nB, -1, 1), 224 | pred_cls.view(nB, -1, self.num_classes), 225 | ), 226 | -1, 227 | ) 228 | return output 229 | 230 | 231 | class Darknet(nn.Module): 232 | """YOLOv3 object detection model""" 233 | 234 | def __init__(self, config_path, img_size=224): 235 | super(Darknet, self).__init__() 236 | self.module_defs = parse_model_config(config_path) 237 | self.hyperparams, self.module_list = create_modules(self.module_defs) 238 | self.img_size = img_size 239 | self.seen = 0 240 | self.header_info = np.array([0, 0, 0, self.seen, 0]) 241 | self.loss_names = ["x", "y", "w", "h", "conf", "cls", "recall", "precision"] 242 | 243 | def forward(self, x, targets=None): 244 | is_training = targets is not None 245 | output = [] 246 | self.losses = defaultdict(float) 247 | layer_outputs = [] 248 | for i, (module_def, module) in enumerate(zip(self.module_defs, self.module_list)): 249 | if module_def["type"] in ["convolutional", "upsample", "maxpool"]: 250 | x = module(x) 251 | elif module_def["type"] == "route": 252 | layer_i = [int(x) for x in module_def["layers"].split(",")] 253 | x = torch.cat([layer_outputs[i] for i in layer_i], 1) 254 | elif module_def["type"] == "shortcut": 255 | layer_i = int(module_def["from"]) 256 | x = layer_outputs[-1] + layer_outputs[layer_i] 257 | elif module_def["type"] == "yolo": 258 | # Train phase: get loss 259 | if is_training: 260 | x, *losses = module[0](x, targets) 261 | for name, loss in zip(self.loss_names, losses): 262 | self.losses[name] += loss 263 | # Test phase: Get detections 264 | else: 265 | x = module(x) 266 | output.append(x) 267 | layer_outputs.append(x) 268 | 269 | self.losses["recall"] /= 3 270 | self.losses["precision"] /= 3 271 | return sum(output) if is_training else torch.cat(output, 1) 272 | 273 | def load_weights(self, weights_path): 274 | """Parses and loads the weights stored in 'weights_path'""" 275 | 276 | # Open the weights file 277 | fp = open(weights_path, "rb") 278 | header = np.fromfile(fp, dtype=np.int32, count=5) # First five are header values 279 | 280 | # Needed to write header when saving weights 281 | self.header_info = header 282 | 283 | self.seen = header[3] 284 | weights = np.fromfile(fp, dtype=np.float32) # The rest are weights 285 | fp.close() 286 | 287 | ptr = 0 288 | for i, (module_def, module) in enumerate(zip(self.module_defs, self.module_list)): 289 | if module_def["type"] == "convolutional": 290 | conv_layer = module[0] 291 | if module_def["batch_normalize"]: 292 | # Load BN bias, weights, running mean and running variance 293 | bn_layer = module[1] 294 | num_b = bn_layer.bias.numel() # Number of biases 295 | # Bias 296 | bn_b = torch.from_numpy(weights[ptr : ptr + num_b]).view_as(bn_layer.bias) 297 | bn_layer.bias.data.copy_(bn_b) 298 | ptr += num_b 299 | # Weight 300 | bn_w = torch.from_numpy(weights[ptr : ptr + num_b]).view_as(bn_layer.weight) 301 | bn_layer.weight.data.copy_(bn_w) 302 | ptr += num_b 303 | # Running Mean 304 | bn_rm = torch.from_numpy(weights[ptr : ptr + num_b]).view_as(bn_layer.running_mean) 305 | bn_layer.running_mean.data.copy_(bn_rm) 306 | ptr += num_b 307 | # Running Var 308 | bn_rv = torch.from_numpy(weights[ptr : ptr + num_b]).view_as(bn_layer.running_var) 309 | bn_layer.running_var.data.copy_(bn_rv) 310 | ptr += num_b 311 | else: 312 | # Load conv. bias 313 | num_b = conv_layer.bias.numel() 314 | conv_b = torch.from_numpy(weights[ptr : ptr + num_b]).view_as(conv_layer.bias) 315 | conv_layer.bias.data.copy_(conv_b) 316 | ptr += num_b 317 | # Load conv. weights 318 | num_w = conv_layer.weight.numel() 319 | conv_w = torch.from_numpy(weights[ptr : ptr + num_w]).view_as(conv_layer.weight) 320 | conv_layer.weight.data.copy_(conv_w) 321 | ptr += num_w 322 | 323 | """ 324 | @:param path - path of the new weights file 325 | @:param cutoff - save layers between 0 and cutoff (cutoff = -1 -> all are saved) 326 | """ 327 | 328 | def save_weights(self, path, cutoff=-1): 329 | 330 | fp = open(path, "wb") 331 | self.header_info[3] = self.seen 332 | self.header_info.tofile(fp) 333 | 334 | # Iterate through layers 335 | for i, (module_def, module) in enumerate(zip(self.module_defs[:cutoff], self.module_list[:cutoff])): 336 | if module_def["type"] == "convolutional": 337 | conv_layer = module[0] 338 | # If batch norm, load bn first 339 | if module_def["batch_normalize"]: 340 | bn_layer = module[1] 341 | bn_layer.bias.data.cpu().numpy().tofile(fp) 342 | bn_layer.weight.data.cpu().numpy().tofile(fp) 343 | bn_layer.running_mean.data.cpu().numpy().tofile(fp) 344 | bn_layer.running_var.data.cpu().numpy().tofile(fp) 345 | # Load conv bias 346 | else: 347 | conv_layer.bias.data.cpu().numpy().tofile(fp) 348 | # Load conv weights 349 | conv_layer.weight.data.cpu().numpy().tofile(fp) 350 | 351 | fp.close() 352 | -------------------------------------------------------------------------------- /detection/report_1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yfeng997/satellite_building_detection.pytorch/e73e8924757abc4ec950d488841df6e48fe4e951/detection/report_1.pdf -------------------------------------------------------------------------------- /detection/requirements.txt: -------------------------------------------------------------------------------- 1 | scikit-image 2 | numpy 3 | torch>=0.4.0 4 | torchvision 5 | pillow 6 | matplotlib 7 | -------------------------------------------------------------------------------- /detection/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 | parser = argparse.ArgumentParser() 23 | parser.add_argument("--batch_size", type=int, default=32, help="size of each image batch") 24 | parser.add_argument("--model_config_path", type=str, default="config/yolov3.cfg", help="path to model config file") 25 | parser.add_argument("--data_config_path", type=str, default="config/res.data", help="path to data config file") 26 | parser.add_argument("--weights_path", type=str, default="", help="path to weights file") 27 | parser.add_argument("--class_path", type=str, default="data/res.names", help="path to class label file") 28 | parser.add_argument("--iou_thres", type=float, default=0.5, help="iou threshold required to qualify as detected") 29 | parser.add_argument("--conf_thres", type=float, default=0.5, help="object confidence threshold") 30 | parser.add_argument("--nms_thres", type=float, default=0.45, help="iou thresshold for non-maximum suppression") 31 | parser.add_argument("--n_cpu", type=int, default=0, help="number of cpu threads to use during batch generation") 32 | parser.add_argument("--img_size", type=int, default=224, help="size of each image dimension") 33 | parser.add_argument("--use_cuda", type=bool, default=True, help="whether to use cuda if available") 34 | opt = parser.parse_args() 35 | print(opt) 36 | 37 | cuda = torch.cuda.is_available() and opt.use_cuda 38 | 39 | # Get data configuration 40 | data_config = parse_data_config(opt.data_config_path) 41 | test_path = data_config["test"] 42 | num_classes = int(data_config["classes"]) 43 | 44 | # Initiate model 45 | model = Darknet(opt.model_config_path) 46 | model.load_weights(opt.weights_path) 47 | 48 | if cuda: 49 | model = model.cuda() 50 | 51 | model.eval() 52 | 53 | # Get dataloader 54 | dataset = ListDataset(test_path) 55 | dataloader = torch.utils.data.DataLoader(dataset, batch_size=opt.batch_size, shuffle=False, num_workers=opt.n_cpu) 56 | 57 | Tensor = torch.cuda.FloatTensor if cuda else torch.FloatTensor 58 | 59 | print("Compute mAP...") 60 | 61 | all_detections = [] 62 | all_annotations = [] 63 | 64 | for batch_i, (_, imgs, targets) in enumerate(tqdm.tqdm(dataloader, desc="Detecting objects")): 65 | 66 | imgs = Variable(imgs.type(Tensor)) 67 | 68 | with torch.no_grad(): 69 | outputs = model(imgs) 70 | outputs = non_max_suppression(outputs, 2, conf_thres=opt.conf_thres, nms_thres=opt.nms_thres) 71 | 72 | for output, annotations in zip(outputs, targets): 73 | 74 | all_detections.append([np.array([]) for _ in range(num_classes)]) 75 | if output is not None: 76 | # Get predicted boxes, confidence scores and labels 77 | pred_boxes = output[:, :5].cpu().numpy() 78 | scores = output[:, 4].cpu().numpy() 79 | pred_labels = output[:, -1].cpu().numpy() 80 | 81 | # Order by confidence 82 | sort_i = np.argsort(scores) 83 | pred_labels = pred_labels[sort_i] 84 | pred_boxes = pred_boxes[sort_i] 85 | 86 | for label in range(num_classes): 87 | all_detections[-1][label] = pred_boxes[pred_labels == label] 88 | 89 | all_annotations.append([np.array([]) for _ in range(num_classes)]) 90 | if any(annotations[:, -1] > 0): 91 | 92 | annotation_labels = annotations[annotations[:, -1] > 0, 0].numpy() 93 | _annotation_boxes = annotations[annotations[:, -1] > 0, 1:] 94 | 95 | # Reformat to x1, y1, x2, y2 and rescale to image dimensions 96 | annotation_boxes = np.empty_like(_annotation_boxes) 97 | annotation_boxes[:, 0] = _annotation_boxes[:, 0] - _annotation_boxes[:, 2] / 2 98 | annotation_boxes[:, 1] = _annotation_boxes[:, 1] - _annotation_boxes[:, 3] / 2 99 | annotation_boxes[:, 2] = _annotation_boxes[:, 0] + _annotation_boxes[:, 2] / 2 100 | annotation_boxes[:, 3] = _annotation_boxes[:, 1] + _annotation_boxes[:, 3] / 2 101 | annotation_boxes *= opt.img_size 102 | 103 | for label in range(num_classes): 104 | all_annotations[-1][label] = annotation_boxes[annotation_labels == label, :] 105 | 106 | average_precisions = {} 107 | for label in range(num_classes): 108 | true_positives = [] 109 | scores = [] 110 | num_annotations = 0 111 | 112 | for i in tqdm.tqdm(range(len(all_annotations)), desc=f"Computing AP for class '{label}'"): 113 | detections = all_detections[i][label] 114 | annotations = all_annotations[i][label] 115 | 116 | num_annotations += annotations.shape[0] 117 | detected_annotations = [] 118 | 119 | for *bbox, score in detections: 120 | scores.append(score) 121 | 122 | if annotations.shape[0] == 0: 123 | true_positives.append(0) 124 | continue 125 | 126 | overlaps = bbox_iou_numpy(np.expand_dims(bbox, axis=0), annotations) 127 | assigned_annotation = np.argmax(overlaps, axis=1) 128 | max_overlap = overlaps[0, assigned_annotation] 129 | 130 | if max_overlap >= opt.iou_thres and assigned_annotation not in detected_annotations: 131 | true_positives.append(1) 132 | detected_annotations.append(assigned_annotation) 133 | else: 134 | true_positives.append(0) 135 | 136 | # no annotations -> AP for this class is 0 137 | if num_annotations == 0: 138 | average_precisions[label] = 0 139 | continue 140 | 141 | true_positives = np.array(true_positives) 142 | false_positives = np.ones_like(true_positives) - true_positives 143 | # sort by score 144 | indices = np.argsort(-np.array(scores)) 145 | false_positives = false_positives[indices] 146 | true_positives = true_positives[indices] 147 | 148 | # compute false positives and true positives 149 | false_positives = np.cumsum(false_positives) 150 | true_positives = np.cumsum(true_positives) 151 | 152 | # compute recall and precision 153 | recall = true_positives / num_annotations 154 | precision = true_positives / np.maximum(true_positives + false_positives, np.finfo(np.float64).eps) 155 | 156 | # compute average precision 157 | average_precision = compute_ap(recall, precision) 158 | average_precisions[label] = average_precision 159 | 160 | print("Average Precisions:") 161 | for c, ap in average_precisions.items(): 162 | print(f"+ Class '{c}' - AP: {ap}") 163 | 164 | mAP = np.mean(list(average_precisions.values())) 165 | print(f"mAP: {mAP}") 166 | -------------------------------------------------------------------------------- /detection/train.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 | 14 | import torch 15 | from torch.utils.data import DataLoader 16 | from torchvision import datasets 17 | from torchvision import transforms 18 | from torch.autograd import Variable 19 | import torch.optim as optim 20 | 21 | parser = argparse.ArgumentParser() 22 | parser.add_argument("--epochs", type=int, default=250, help="number of epochs") 23 | parser.add_argument("--image_folder", type=str, default="/data/feng/building-detect/images", help="path to dataset") 24 | parser.add_argument("--batch_size", type=int, default=32, help="size of each image batch") 25 | parser.add_argument("--model_config_path", type=str, default="config/yolov3.cfg", help="path to model config file") 26 | parser.add_argument("--data_config_path", type=str, default="config/res.data", help="path to data config file") 27 | parser.add_argument("--weights_path", type=str, default="", help="path to weights file") 28 | parser.add_argument("--class_path", type=str, default="data/res.names", help="path to class label file") 29 | parser.add_argument("--conf_thres", type=float, default=0.8, help="object confidence threshold") 30 | parser.add_argument("--nms_thres", type=float, default=0.4, help="iou thresshold for non-maximum suppression") 31 | parser.add_argument("--n_cpu", type=int, default=0, help="number of cpu threads to use during batch generation") 32 | parser.add_argument("--img_size", type=int, default=224, help="size of each image dimension") 33 | parser.add_argument("--checkpoint_interval", type=int, default=30, help="interval between saving model weights") 34 | parser.add_argument( 35 | "--checkpoint_dir", type=str, default="checkpoints", help="directory where model checkpoints are saved" 36 | ) 37 | parser.add_argument("--use_cuda", type=bool, default=True, help="whether to use cuda if available") 38 | opt = parser.parse_args() 39 | print(opt) 40 | 41 | cuda = torch.cuda.is_available() and opt.use_cuda 42 | 43 | os.makedirs("output", exist_ok=True) 44 | os.makedirs("checkpoints", exist_ok=True) 45 | 46 | classes = load_classes(opt.class_path) 47 | 48 | # Get data configuration 49 | data_config = parse_data_config(opt.data_config_path) 50 | train_path = data_config["train"] 51 | 52 | # Get hyper parameters 53 | hyperparams = parse_model_config(opt.model_config_path)[0] 54 | learning_rate = float(hyperparams["learning_rate"]) 55 | momentum = float(hyperparams["momentum"]) 56 | decay = float(hyperparams["decay"]) 57 | burn_in = int(hyperparams["burn_in"]) 58 | 59 | # Initiate model 60 | model = Darknet(opt.model_config_path, img_size=opt.img_size) 61 | model.apply(weights_init_normal) 62 | model.load_state_dict(torch.load(opt.weights_path)) 63 | # load [Epoch 0/150, Batch 0/242] [Losses: x 0.263783, y 0.242547, w 7.087229, h 5.045750, conf 4.708252, cls 0.039098, total 17.386658, recall: 0.07182, precision: 0.00829] 64 | # without [Epoch 0/150, Batch 0/242] [Losses: x 0.291999, y 0.240591, w 3.382115, h 3.164990, conf 4.359457, cls 0.063323, total 11.502476, recall: 0.12891, precision: 0.00100] 65 | 66 | if cuda: 67 | model = model.cuda() 68 | 69 | model.train() 70 | 71 | # Get dataloader 72 | dataloader = torch.utils.data.DataLoader( 73 | ListDataset(train_path, img_size=opt.img_size), batch_size=opt.batch_size, shuffle=False, num_workers=opt.n_cpu 74 | ) 75 | 76 | Tensor = torch.cuda.FloatTensor if cuda else torch.FloatTensor 77 | 78 | optimizer = torch.optim.Adam(filter(lambda p: p.requires_grad, model.parameters())) 79 | 80 | # catch up to trained model's optimizer step 81 | for i in range(120 * 242): 82 | optimizer.zero_grad() 83 | optimizer.step() 84 | 85 | for epoch in range(opt.epochs): 86 | for batch_i, (_, imgs, targets) in enumerate(dataloader): 87 | imgs = Variable(imgs.type(Tensor)) 88 | targets = Variable(targets.type(Tensor), requires_grad=False) 89 | 90 | optimizer.zero_grad() 91 | 92 | loss = model(imgs, targets) 93 | 94 | loss.backward() 95 | optimizer.step() 96 | 97 | if (batch_i % 100) == 0: 98 | print( 99 | "[Epoch %d/%d, Batch %d/%d] [Losses: x %f, y %f, w %f, h %f, conf %f, cls %f, total %f, recall: %.5f, precision: %.5f]" 100 | % ( 101 | epoch, 102 | opt.epochs, 103 | batch_i, 104 | len(dataloader), 105 | model.losses["x"], 106 | model.losses["y"], 107 | model.losses["w"], 108 | model.losses["h"], 109 | model.losses["conf"], 110 | model.losses["cls"], 111 | loss.item(), 112 | model.losses["recall"], 113 | model.losses["precision"], 114 | ) 115 | ) 116 | 117 | model.seen += imgs.size(0) 118 | 119 | if epoch % opt.checkpoint_interval == 0: 120 | torch.save(model.state_dict(), "%s/%d.weights" % (opt.checkpoint_dir, epoch)) 121 | # print('weight is saved as %d.weights' % epoch) 122 | # model.load_state_dict(torch.load(opt.weights_path)) 123 | # loss = model(imgs, targets) 124 | # print('printing saved weight loss: %f' % loss.item()) 125 | -------------------------------------------------------------------------------- /detection/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yfeng997/satellite_building_detection.pytorch/e73e8924757abc4ec950d488841df6e48fe4e951/detection/utils/__init__.py -------------------------------------------------------------------------------- /detection/utils/__pycache__/__init__.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yfeng997/satellite_building_detection.pytorch/e73e8924757abc4ec950d488841df6e48fe4e951/detection/utils/__pycache__/__init__.cpython-36.pyc -------------------------------------------------------------------------------- /detection/utils/__pycache__/datasets.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yfeng997/satellite_building_detection.pytorch/e73e8924757abc4ec950d488841df6e48fe4e951/detection/utils/__pycache__/datasets.cpython-36.pyc -------------------------------------------------------------------------------- /detection/utils/__pycache__/parse_config.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yfeng997/satellite_building_detection.pytorch/e73e8924757abc4ec950d488841df6e48fe4e951/detection/utils/__pycache__/parse_config.cpython-36.pyc -------------------------------------------------------------------------------- /detection/utils/__pycache__/utils.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yfeng997/satellite_building_detection.pytorch/e73e8924757abc4ec950d488841df6e48fe4e951/detection/utils/__pycache__/utils.cpython-36.pyc -------------------------------------------------------------------------------- /detection/utils/datasets.py: -------------------------------------------------------------------------------- 1 | import glob 2 | import random 3 | import os 4 | import numpy as np 5 | import json 6 | import torch 7 | import cv2 8 | from torch.utils.data import Dataset 9 | from PIL import Image 10 | import torchvision.transforms as transforms 11 | 12 | import matplotlib.pyplot as plt 13 | import matplotlib.patches as patches 14 | 15 | from skimage.transform import resize 16 | 17 | import sys 18 | 19 | class ImageFolder(Dataset): 20 | def __init__(self, folder_path, img_size=416): 21 | self.files = sorted(glob.glob('%s/*.*' % folder_path)) 22 | self.img_shape = (img_size, img_size) 23 | 24 | def __getitem__(self, index): 25 | img_path = self.files[index % len(self.files)] 26 | # Extract image 27 | img = np.array(Image.open(img_path)) 28 | h, w, _ = img.shape 29 | dim_diff = np.abs(h - w) 30 | # Upper (left) and lower (right) padding 31 | pad1, pad2 = dim_diff // 2, dim_diff - dim_diff // 2 32 | # Determine padding 33 | pad = ((pad1, pad2), (0, 0), (0, 0)) if h <= w else ((0, 0), (pad1, pad2), (0, 0)) 34 | # Add padding 35 | input_img = np.pad(img, pad, 'constant', constant_values=127.5) / 255. 36 | # Resize and normalize 37 | input_img = resize(input_img, (*self.img_shape, 3), mode='reflect') 38 | # Channels-first 39 | input_img = np.transpose(input_img, (2, 0, 1)) 40 | # As pytorch tensor 41 | input_img = torch.from_numpy(input_img).float() 42 | 43 | return img_path, input_img 44 | 45 | def __len__(self): 46 | return len(self.files) 47 | 48 | 49 | class ListDataset(Dataset): 50 | def __init__(self, list_path, img_size=224): 51 | with open(list_path, 'r') as file: 52 | self.img_files = file.readlines() 53 | self.label_files = [path.replace('images', 'annotations').replace('.png', '.json').replace('.jpg', '.json') for path in self.img_files] 54 | self.img_shape = (img_size, img_size) 55 | self.max_objects = 50 56 | 57 | def __getitem__(self, index): 58 | 59 | #--------- 60 | # Image 61 | #--------- 62 | 63 | img_path = self.img_files[index % len(self.img_files)].rstrip() 64 | img = np.array(Image.open(img_path)) 65 | 66 | # Handles images with less than three channels 67 | while len(img.shape) != 3: 68 | index += 1 69 | img_path = self.img_files[index % len(self.img_files)].rstrip() 70 | img = np.array(Image.open(img_path)) 71 | 72 | h, w, _ = img.shape 73 | dim_diff = np.abs(h - w) 74 | # Upper (left) and lower (right) padding 75 | pad1, pad2 = dim_diff // 2, dim_diff - dim_diff // 2 76 | # Determine padding 77 | pad = ((pad1, pad2), (0, 0), (0, 0)) if h <= w else ((0, 0), (pad1, pad2), (0, 0)) 78 | # Add padding 79 | input_img = np.pad(img, pad, 'constant', constant_values=128) / 255. 80 | padded_h, padded_w, _ = input_img.shape 81 | # Resize and normalize 82 | input_img = resize(input_img, (*self.img_shape, 3), mode='reflect') 83 | # Channels-first 84 | input_img = np.transpose(input_img, (2, 0, 1)) 85 | # As pytorch tensor 86 | input_img = torch.from_numpy(input_img).float() 87 | 88 | #--------- 89 | # Label 90 | #--------- 91 | 92 | # raw_image = cv2.imread(img_path) 93 | 94 | label_path = self.label_files[index % len(self.img_files)].rstrip() 95 | 96 | labels = [] 97 | if os.path.exists(label_path): 98 | with open(label_path, 'r') as f: 99 | # [{class: class, bbox: [xywh]}] 100 | raw_labels = json.load(f) 101 | for raw_label in raw_labels: 102 | class_label = int(raw_label['class']) 103 | bbox = raw_label['bbox'] 104 | # ASSUME we do not need to pad 105 | x_c = bbox[0] + bbox[2]/2 106 | y_c = bbox[1] + bbox[3]/2 107 | w = bbox[2] 108 | h = bbox[3] 109 | labels.append([class_label, x_c, y_c, w, h]) 110 | 111 | # x = int(bbox[0] * 224) 112 | # y = int(bbox[1] * 224) 113 | # w = int(bbox[2] * 224) 114 | # h = int(bbox[3] * 224) 115 | # if class_label == 0: 116 | # cv2.rectangle(raw_image, (x, y), (x+w, y+h), (255,0,0), 1) 117 | # else: 118 | # cv2.rectangle(raw_image, (x, y), (x+w, y+h), (0,255,0), 1) 119 | # labels = np.loadtxt(label_path).reshape(-1, 5) 120 | # # Extract coordinates for unpadded + unscaled image 121 | # x1 = w * (labels[:, 1] - labels[:, 3]/2) 122 | # y1 = h * (labels[:, 2] - labels[:, 4]/2) 123 | # x2 = w * (labels[:, 1] + labels[:, 3]/2) 124 | # y2 = h * (labels[:, 2] + labels[:, 4]/2) 125 | # # Adjust for added padding 126 | # x1 += pad[1][0] 127 | # y1 += pad[0][0] 128 | # x2 += pad[1][0] 129 | # y2 += pad[0][0] 130 | # # Calculate ratios from coordinates 131 | # labels[:, 1] = ((x1 + x2) / 2) / padded_w 132 | # labels[:, 2] = ((y1 + y2) / 2) / padded_h 133 | # labels[:, 3] *= w / padded_w 134 | # labels[:, 4] *= h / padded_h 135 | # imagepathh = img_path.split('/')[-1] 136 | # cv2.imwrite('/home/yuansong/code/building-detection/tmp/'+imagepathh, raw_image) 137 | # Fill matrix 138 | filled_labels = np.zeros((self.max_objects, 5)) 139 | if not len(labels) == 0: 140 | filled_labels[range(len(labels))[:self.max_objects]] = labels[:self.max_objects] 141 | filled_labels = torch.from_numpy(filled_labels) 142 | 143 | return img_path, input_img, filled_labels 144 | 145 | def __len__(self): 146 | return len(self.img_files) 147 | -------------------------------------------------------------------------------- /detection/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' 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 | -------------------------------------------------------------------------------- /detection/utils/utils.py: -------------------------------------------------------------------------------- 1 | from __future__ import division 2 | import math 3 | import time 4 | import torch 5 | import torch.nn as nn 6 | import torch.nn.functional as F 7 | from torch.autograd import Variable 8 | import numpy as np 9 | 10 | import matplotlib.pyplot as plt 11 | import matplotlib.patches as patches 12 | 13 | 14 | def load_classes(path): 15 | """ 16 | Loads class labels at 'path' 17 | """ 18 | fp = open(path, "r") 19 | names = fp.read().split("\n")[:-1] 20 | return names 21 | 22 | 23 | def weights_init_normal(m): 24 | classname = m.__class__.__name__ 25 | if classname.find("Conv") != -1: 26 | torch.nn.init.normal_(m.weight.data, 0.0, 0.02) 27 | elif classname.find("BatchNorm2d") != -1: 28 | torch.nn.init.normal_(m.weight.data, 1.0, 0.02) 29 | torch.nn.init.constant_(m.bias.data, 0.0) 30 | 31 | 32 | def compute_ap(recall, precision): 33 | """ Compute the average precision, given the recall and precision curves. 34 | Code originally from https://github.com/rbgirshick/py-faster-rcnn. 35 | 36 | # Arguments 37 | recall: The recall curve (list). 38 | precision: The precision curve (list). 39 | # Returns 40 | The average precision as computed in py-faster-rcnn. 41 | """ 42 | # correct AP calculation 43 | # first append sentinel values at the end 44 | mrec = np.concatenate(([0.0], recall, [1.0])) 45 | mpre = np.concatenate(([0.0], precision, [0.0])) 46 | 47 | # compute the precision envelope 48 | for i in range(mpre.size - 1, 0, -1): 49 | mpre[i - 1] = np.maximum(mpre[i - 1], mpre[i]) 50 | 51 | # to calculate area under PR curve, look for points 52 | # where X axis (recall) changes value 53 | i = np.where(mrec[1:] != mrec[:-1])[0] 54 | 55 | # and sum (\Delta recall) * prec 56 | ap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1]) 57 | return ap 58 | 59 | 60 | def bbox_iou(box1, box2, x1y1x2y2=True): 61 | """ 62 | Returns the IoU of two bounding boxes 63 | """ 64 | if not x1y1x2y2: 65 | # Transform from center and width to exact coordinates 66 | b1_x1, b1_x2 = box1[:, 0] - box1[:, 2] / 2, box1[:, 0] + box1[:, 2] / 2 67 | b1_y1, b1_y2 = box1[:, 1] - box1[:, 3] / 2, box1[:, 1] + box1[:, 3] / 2 68 | b2_x1, b2_x2 = box2[:, 0] - box2[:, 2] / 2, box2[:, 0] + box2[:, 2] / 2 69 | b2_y1, b2_y2 = box2[:, 1] - box2[:, 3] / 2, box2[:, 1] + box2[:, 3] / 2 70 | else: 71 | # Get the coordinates of bounding boxes 72 | b1_x1, b1_y1, b1_x2, b1_y2 = box1[:, 0], box1[:, 1], box1[:, 2], box1[:, 3] 73 | b2_x1, b2_y1, b2_x2, b2_y2 = box2[:, 0], box2[:, 1], box2[:, 2], box2[:, 3] 74 | 75 | # get the corrdinates of the intersection rectangle 76 | inter_rect_x1 = torch.max(b1_x1, b2_x1) 77 | inter_rect_y1 = torch.max(b1_y1, b2_y1) 78 | inter_rect_x2 = torch.min(b1_x2, b2_x2) 79 | inter_rect_y2 = torch.min(b1_y2, b2_y2) 80 | # Intersection area 81 | inter_area = torch.clamp(inter_rect_x2 - inter_rect_x1 + 1, min=0) * torch.clamp( 82 | inter_rect_y2 - inter_rect_y1 + 1, min=0 83 | ) 84 | # Union Area 85 | b1_area = (b1_x2 - b1_x1 + 1) * (b1_y2 - b1_y1 + 1) 86 | b2_area = (b2_x2 - b2_x1 + 1) * (b2_y2 - b2_y1 + 1) 87 | 88 | iou = inter_area / (b1_area + b2_area - inter_area + 1e-16) 89 | 90 | return iou 91 | 92 | 93 | def bbox_iou_numpy(box1, box2): 94 | """Computes IoU between bounding boxes. 95 | Parameters 96 | ---------- 97 | box1 : ndarray 98 | (N, 4) shaped array with bboxes 99 | box2 : ndarray 100 | (M, 4) shaped array with bboxes 101 | Returns 102 | ------- 103 | : ndarray 104 | (N, M) shaped array with IoUs 105 | """ 106 | area = (box2[:, 2] - box2[:, 0]) * (box2[:, 3] - box2[:, 1]) 107 | 108 | iw = np.minimum(np.expand_dims(box1[:, 2], axis=1), box2[:, 2]) - np.maximum( 109 | np.expand_dims(box1[:, 0], 1), box2[:, 0] 110 | ) 111 | ih = np.minimum(np.expand_dims(box1[:, 3], axis=1), box2[:, 3]) - np.maximum( 112 | np.expand_dims(box1[:, 1], 1), box2[:, 1] 113 | ) 114 | 115 | iw = np.maximum(iw, 0) 116 | ih = np.maximum(ih, 0) 117 | 118 | ua = np.expand_dims((box1[:, 2] - box1[:, 0]) * (box1[:, 3] - box1[:, 1]), axis=1) + area - iw * ih 119 | 120 | ua = np.maximum(ua, np.finfo(float).eps) 121 | 122 | intersection = iw * ih 123 | 124 | return intersection / ua 125 | 126 | 127 | def non_max_suppression(prediction, num_classes, conf_thres=0.5, nms_thres=0.4): 128 | """ 129 | Removes detections with lower object confidence score than 'conf_thres' and performs 130 | Non-Maximum Suppression to further filter detections. 131 | Returns detections with shape: 132 | (x1, y1, x2, y2, object_conf, class_score, class_pred) 133 | """ 134 | 135 | # From (center x, center y, width, height) to (x1, y1, x2, y2) 136 | box_corner = prediction.new(prediction.shape) 137 | box_corner[:, :, 0] = prediction[:, :, 0] - prediction[:, :, 2] / 2 138 | box_corner[:, :, 1] = prediction[:, :, 1] - prediction[:, :, 3] / 2 139 | box_corner[:, :, 2] = prediction[:, :, 0] + prediction[:, :, 2] / 2 140 | box_corner[:, :, 3] = prediction[:, :, 1] + prediction[:, :, 3] / 2 141 | prediction[:, :, :4] = box_corner[:, :, :4] 142 | 143 | output = [None for _ in range(len(prediction))] 144 | for image_i, image_pred in enumerate(prediction): 145 | # Filter out confidence scores below threshold 146 | conf_mask = (image_pred[:, 4] >= conf_thres).squeeze() 147 | image_pred = image_pred[conf_mask] 148 | # If none are remaining => process next image 149 | if not image_pred.size(0): 150 | continue 151 | # Get score and class with highest confidence 152 | class_conf, class_pred = torch.max(image_pred[:, 5 : 5 + num_classes], 1, keepdim=True) 153 | # Detections ordered as (x1, y1, x2, y2, obj_conf, class_conf, class_pred) 154 | detections = torch.cat((image_pred[:, :5], class_conf.float(), class_pred.float()), 1) 155 | # Iterate through all predicted classes 156 | unique_labels = detections[:, -1].cpu().unique() 157 | if prediction.is_cuda: 158 | unique_labels = unique_labels.cuda() 159 | for c in unique_labels: 160 | # Get the detections with the particular class 161 | detections_class = detections[detections[:, -1] == c] 162 | # Sort the detections by maximum objectness confidence 163 | _, conf_sort_index = torch.sort(detections_class[:, 4], descending=True) 164 | detections_class = detections_class[conf_sort_index] 165 | # Perform non-maximum suppression 166 | max_detections = [] 167 | while detections_class.size(0): 168 | # Get detection with highest confidence and save as max detection 169 | max_detections.append(detections_class[0].unsqueeze(0)) 170 | # Stop if we're at the last detection 171 | if len(detections_class) == 1: 172 | break 173 | # Get the IOUs for all boxes with lower confidence 174 | ious = bbox_iou(max_detections[-1], detections_class[1:]) 175 | # Remove detections with IoU >= NMS threshold 176 | detections_class = detections_class[1:][ious < nms_thres] 177 | 178 | max_detections = torch.cat(max_detections).data 179 | # Add max detections to outputs 180 | output[image_i] = ( 181 | max_detections if output[image_i] is None else torch.cat((output[image_i], max_detections)) 182 | ) 183 | 184 | return output 185 | 186 | 187 | def build_targets( 188 | pred_boxes, pred_conf, pred_cls, target, anchors, num_anchors, num_classes, grid_size, ignore_thres, img_dim 189 | ): 190 | nB = target.size(0) 191 | nA = num_anchors 192 | nC = num_classes 193 | nG = grid_size 194 | mask = torch.zeros(nB, nA, nG, nG) 195 | conf_mask = torch.ones(nB, nA, nG, nG) 196 | tx = torch.zeros(nB, nA, nG, nG) 197 | ty = torch.zeros(nB, nA, nG, nG) 198 | tw = torch.zeros(nB, nA, nG, nG) 199 | th = torch.zeros(nB, nA, nG, nG) 200 | tconf = torch.ByteTensor(nB, nA, nG, nG).fill_(0) 201 | tcls = torch.ByteTensor(nB, nA, nG, nG, nC).fill_(0) 202 | 203 | nGT = 0 204 | nCorrect = 0 205 | for b in range(nB): 206 | for t in range(target.shape[1]): 207 | if target[b, t].sum() == 0: 208 | continue 209 | nGT += 1 210 | # Convert to position relative to box 211 | gx = target[b, t, 1] * nG 212 | gy = target[b, t, 2] * nG 213 | gw = target[b, t, 3] * nG 214 | gh = target[b, t, 4] * nG 215 | # Get grid box indices 216 | gi = int(gx) 217 | gj = int(gy) 218 | # Get shape of gt box 219 | gt_box = torch.FloatTensor(np.array([0, 0, gw, gh])).unsqueeze(0) 220 | # Get shape of anchor box 221 | anchor_shapes = torch.FloatTensor(np.concatenate((np.zeros((len(anchors), 2)), np.array(anchors)), 1)) 222 | # Calculate iou between gt and anchor shapes 223 | anch_ious = bbox_iou(gt_box, anchor_shapes) 224 | # Where the overlap is larger than threshold set mask to zero (ignore) 225 | conf_mask[b, anch_ious > ignore_thres, gj, gi] = 0 226 | # Find the best matching anchor box 227 | best_n = np.argmax(anch_ious) 228 | # Get ground truth box 229 | gt_box = torch.FloatTensor(np.array([gx, gy, gw, gh])).unsqueeze(0) 230 | # Get the best prediction 231 | pred_box = pred_boxes[b, best_n, gj, gi].unsqueeze(0) 232 | # Masks 233 | mask[b, best_n, gj, gi] = 1 234 | conf_mask[b, best_n, gj, gi] = 1 235 | # Coordinates 236 | tx[b, best_n, gj, gi] = gx - gi 237 | ty[b, best_n, gj, gi] = gy - gj 238 | # Width and height 239 | tw[b, best_n, gj, gi] = math.log(gw / anchors[best_n][0] + 1e-16) 240 | th[b, best_n, gj, gi] = math.log(gh / anchors[best_n][1] + 1e-16) 241 | # One-hot encoding of label 242 | target_label = int(target[b, t, 0]) 243 | tcls[b, best_n, gj, gi, target_label] = 1 244 | tconf[b, best_n, gj, gi] = 1 245 | 246 | # Calculate iou between ground truth and best matching prediction 247 | iou = bbox_iou(gt_box, pred_box, x1y1x2y2=False) 248 | pred_label = torch.argmax(pred_cls[b, best_n, gj, gi]) 249 | score = pred_conf[b, best_n, gj, gi] 250 | if iou > 0.5 and pred_label == target_label and score > 0.5: 251 | nCorrect += 1 252 | 253 | return nGT, nCorrect, mask, conf_mask, tx, ty, tw, th, tconf, tcls 254 | 255 | 256 | def to_categorical(y, num_classes): 257 | """ 1-hot encodes a tensor """ 258 | return torch.from_numpy(np.eye(num_classes, dtype="uint8")[y]) 259 | -------------------------------------------------------------------------------- /detection/visualize.py: -------------------------------------------------------------------------------- 1 | import os 2 | import json 3 | import cv2 4 | 5 | images_dir = './tmp_images' 6 | annotations_dir = './tmp_annotations' 7 | vis_dir = './vis' 8 | 9 | for root, dirs, files in os.walk(images_dir): 10 | for filename in files: 11 | if filename.endswith('.jpg'): 12 | annotation_file = os.path.join(annotations_dir, filename[:-4]+'.json') 13 | with open(annotation_file, 'r') as f: 14 | annotation = json.load(f) 15 | raw_image = cv2.imread(os.path.join(images_dir, filename)) 16 | for anno in annotation: 17 | bbox = anno['bbox'] 18 | label = anno['class'] 19 | x = int(bbox[0] * 224) 20 | y = int(bbox[1] * 224) 21 | w = int(bbox[2] * 224) 22 | h = int(bbox[3] * 224) 23 | if label == 1: 24 | cv2.rectangle(raw_image, (x, y), (x+w, y+h), (255,0,0), 1) 25 | else: 26 | cv2.rectangle(raw_image, (x, y), (x+w, y+h), (0,255,0), 1) 27 | cv2.imwrite(os.path.join(vis_dir, filename), raw_image) -------------------------------------------------------------------------------- /new_detection/.gitignore: -------------------------------------------------------------------------------- 1 | checkpoints/* 2 | __pycache__/* 3 | output/* 4 | acc.jpg 5 | loss.jpg 6 | log.txt 7 | eval_result.json -------------------------------------------------------------------------------- /new_detection/best_practice.txt: -------------------------------------------------------------------------------- 1 | Use as small a network as possible at first. 2 | The current fasterrcnn_resnet18_fpn has 21M parameters. 3 | Official resnet18 from PyTorch has 11M parameters, which should be a 4 | good guideline adjusting the number of model parameters. 5 | 6 | Try to overfit a small dataset first(one image), and observe train/val loss 7 | and accuracy. -------------------------------------------------------------------------------- /new_detection/config/res.data: -------------------------------------------------------------------------------- 1 | classes= 2 2 | train=/data/feng/building-detect/config/train_config.txt 3 | test=/data/feng/building-detect/config/test_config.txt 4 | names=data/res.names 5 | backup=backup/ 6 | -------------------------------------------------------------------------------- /new_detection/config/test_config.txt: -------------------------------------------------------------------------------- 1 | /data/feng/building-detect/images/12838.jpg 2 | /data/feng/building-detect/images/14905.jpg 3 | /data/feng/building-detect/images/12223.jpg 4 | /data/feng/building-detect/images/9871.jpg 5 | /data/feng/building-detect/images/10818.jpg 6 | /data/feng/building-detect/images/6243.jpg 7 | /data/feng/building-detect/images/10555.jpg 8 | /data/feng/building-detect/images/14196.jpg 9 | /data/feng/building-detect/images/4117.jpg 10 | /data/feng/building-detect/images/441.jpg 11 | /data/feng/building-detect/images/13698.jpg 12 | /data/feng/building-detect/images/2656.jpg 13 | /data/feng/building-detect/images/13585.jpg 14 | /data/feng/building-detect/images/14788.jpg 15 | /data/feng/building-detect/images/2473.jpg 16 | /data/feng/building-detect/images/5640.jpg 17 | /data/feng/building-detect/images/2895.jpg 18 | /data/feng/building-detect/images/12284.jpg 19 | /data/feng/building-detect/images/10391.jpg 20 | /data/feng/building-detect/images/1411.jpg 21 | /data/feng/building-detect/images/570.jpg 22 | /data/feng/building-detect/images/10655.jpg 23 | /data/feng/building-detect/images/13489.jpg 24 | /data/feng/building-detect/images/10351.jpg 25 | /data/feng/building-detect/images/1175.jpg 26 | /data/feng/building-detect/images/13710.jpg 27 | /data/feng/building-detect/images/8799.jpg 28 | /data/feng/building-detect/images/13845.jpg 29 | /data/feng/building-detect/images/12916.jpg 30 | /data/feng/building-detect/images/12308.jpg 31 | /data/feng/building-detect/images/8632.jpg 32 | /data/feng/building-detect/images/6186.jpg 33 | /data/feng/building-detect/images/7763.jpg 34 | /data/feng/building-detect/images/3495.jpg 35 | /data/feng/building-detect/images/965.jpg 36 | /data/feng/building-detect/images/4612.jpg 37 | /data/feng/building-detect/images/13386.jpg 38 | /data/feng/building-detect/images/9994.jpg 39 | /data/feng/building-detect/images/8630.jpg 40 | /data/feng/building-detect/images/589.jpg 41 | /data/feng/building-detect/images/12723.jpg 42 | /data/feng/building-detect/images/7168.jpg 43 | /data/feng/building-detect/images/12008.jpg 44 | /data/feng/building-detect/images/12015.jpg 45 | /data/feng/building-detect/images/6295.jpg 46 | /data/feng/building-detect/images/2650.jpg 47 | /data/feng/building-detect/images/8133.jpg 48 | /data/feng/building-detect/images/145.jpg 49 | /data/feng/building-detect/images/698.jpg 50 | /data/feng/building-detect/images/10126.jpg 51 | /data/feng/building-detect/images/15136.jpg 52 | /data/feng/building-detect/images/13355.jpg 53 | /data/feng/building-detect/images/12174.jpg 54 | /data/feng/building-detect/images/6283.jpg 55 | /data/feng/building-detect/images/5893.jpg 56 | /data/feng/building-detect/images/389.jpg 57 | /data/feng/building-detect/images/3124.jpg 58 | /data/feng/building-detect/images/11304.jpg 59 | /data/feng/building-detect/images/3219.jpg 60 | /data/feng/building-detect/images/1582.jpg 61 | /data/feng/building-detect/images/8536.jpg 62 | /data/feng/building-detect/images/3731.jpg 63 | /data/feng/building-detect/images/4767.jpg 64 | /data/feng/building-detect/images/12860.jpg 65 | /data/feng/building-detect/images/11492.jpg 66 | /data/feng/building-detect/images/10074.jpg 67 | /data/feng/building-detect/images/8681.jpg 68 | /data/feng/building-detect/images/5963.jpg 69 | /data/feng/building-detect/images/13360.jpg 70 | /data/feng/building-detect/images/12164.jpg 71 | /data/feng/building-detect/images/550.jpg 72 | /data/feng/building-detect/images/14225.jpg 73 | /data/feng/building-detect/images/605.jpg 74 | /data/feng/building-detect/images/3486.jpg 75 | /data/feng/building-detect/images/3345.jpg 76 | /data/feng/building-detect/images/11010.jpg 77 | /data/feng/building-detect/images/9202.jpg 78 | /data/feng/building-detect/images/11055.jpg 79 | /data/feng/building-detect/images/11225.jpg 80 | /data/feng/building-detect/images/11656.jpg 81 | /data/feng/building-detect/images/13034.jpg 82 | /data/feng/building-detect/images/9087.jpg 83 | /data/feng/building-detect/images/14677.jpg 84 | /data/feng/building-detect/images/842.jpg 85 | /data/feng/building-detect/images/7364.jpg 86 | /data/feng/building-detect/images/14194.jpg 87 | /data/feng/building-detect/images/14344.jpg 88 | /data/feng/building-detect/images/9595.jpg 89 | /data/feng/building-detect/images/3040.jpg 90 | /data/feng/building-detect/images/1583.jpg 91 | /data/feng/building-detect/images/2924.jpg 92 | /data/feng/building-detect/images/14551.jpg 93 | /data/feng/building-detect/images/3659.jpg 94 | /data/feng/building-detect/images/369.jpg 95 | /data/feng/building-detect/images/4006.jpg 96 | /data/feng/building-detect/images/13525.jpg 97 | /data/feng/building-detect/images/6705.jpg 98 | /data/feng/building-detect/images/9602.jpg 99 | /data/feng/building-detect/images/7653.jpg 100 | /data/feng/building-detect/images/3530.jpg 101 | /data/feng/building-detect/images/7631.jpg 102 | /data/feng/building-detect/images/14314.jpg 103 | /data/feng/building-detect/images/7273.jpg 104 | /data/feng/building-detect/images/15066.jpg 105 | /data/feng/building-detect/images/10380.jpg 106 | /data/feng/building-detect/images/9865.jpg 107 | /data/feng/building-detect/images/6995.jpg 108 | /data/feng/building-detect/images/7376.jpg 109 | /data/feng/building-detect/images/10731.jpg 110 | /data/feng/building-detect/images/6558.jpg 111 | /data/feng/building-detect/images/10019.jpg 112 | /data/feng/building-detect/images/13748.jpg 113 | /data/feng/building-detect/images/9729.jpg 114 | /data/feng/building-detect/images/5283.jpg 115 | /data/feng/building-detect/images/3359.jpg 116 | /data/feng/building-detect/images/4682.jpg 117 | /data/feng/building-detect/images/6798.jpg 118 | /data/feng/building-detect/images/10824.jpg 119 | /data/feng/building-detect/images/6891.jpg 120 | /data/feng/building-detect/images/2881.jpg 121 | /data/feng/building-detect/images/2311.jpg 122 | /data/feng/building-detect/images/9045.jpg 123 | /data/feng/building-detect/images/9989.jpg 124 | /data/feng/building-detect/images/6831.jpg 125 | /data/feng/building-detect/images/13335.jpg 126 | /data/feng/building-detect/images/8070.jpg 127 | /data/feng/building-detect/images/1137.jpg 128 | /data/feng/building-detect/images/14437.jpg 129 | /data/feng/building-detect/images/6348.jpg 130 | /data/feng/building-detect/images/7812.jpg 131 | /data/feng/building-detect/images/5038.jpg 132 | /data/feng/building-detect/images/13828.jpg 133 | /data/feng/building-detect/images/5512.jpg 134 | /data/feng/building-detect/images/9094.jpg 135 | /data/feng/building-detect/images/5201.jpg 136 | /data/feng/building-detect/images/13574.jpg 137 | /data/feng/building-detect/images/3410.jpg 138 | /data/feng/building-detect/images/11060.jpg 139 | /data/feng/building-detect/images/8708.jpg 140 | /data/feng/building-detect/images/13759.jpg 141 | /data/feng/building-detect/images/12705.jpg 142 | /data/feng/building-detect/images/1366.jpg 143 | /data/feng/building-detect/images/14358.jpg 144 | /data/feng/building-detect/images/2521.jpg 145 | /data/feng/building-detect/images/10709.jpg 146 | /data/feng/building-detect/images/1373.jpg 147 | /data/feng/building-detect/images/1301.jpg 148 | /data/feng/building-detect/images/4433.jpg 149 | /data/feng/building-detect/images/12692.jpg 150 | /data/feng/building-detect/images/10172.jpg 151 | /data/feng/building-detect/images/2075.jpg 152 | /data/feng/building-detect/images/2513.jpg 153 | /data/feng/building-detect/images/3446.jpg 154 | /data/feng/building-detect/images/14460.jpg 155 | /data/feng/building-detect/images/9544.jpg 156 | /data/feng/building-detect/images/5468.jpg 157 | /data/feng/building-detect/images/13460.jpg 158 | /data/feng/building-detect/images/8033.jpg 159 | /data/feng/building-detect/images/2081.jpg 160 | /data/feng/building-detect/images/7211.jpg 161 | /data/feng/building-detect/images/11807.jpg 162 | /data/feng/building-detect/images/6319.jpg 163 | /data/feng/building-detect/images/14299.jpg 164 | /data/feng/building-detect/images/5239.jpg 165 | /data/feng/building-detect/images/8928.jpg 166 | /data/feng/building-detect/images/9777.jpg 167 | /data/feng/building-detect/images/8200.jpg 168 | /data/feng/building-detect/images/13493.jpg 169 | /data/feng/building-detect/images/2154.jpg 170 | /data/feng/building-detect/images/8929.jpg 171 | /data/feng/building-detect/images/14497.jpg 172 | /data/feng/building-detect/images/9060.jpg 173 | /data/feng/building-detect/images/13273.jpg 174 | /data/feng/building-detect/images/3289.jpg 175 | /data/feng/building-detect/images/10239.jpg 176 | /data/feng/building-detect/images/3083.jpg 177 | /data/feng/building-detect/images/642.jpg 178 | /data/feng/building-detect/images/7760.jpg 179 | /data/feng/building-detect/images/6064.jpg 180 | /data/feng/building-detect/images/3092.jpg 181 | /data/feng/building-detect/images/14698.jpg 182 | /data/feng/building-detect/images/8575.jpg 183 | /data/feng/building-detect/images/2673.jpg 184 | /data/feng/building-detect/images/13930.jpg 185 | /data/feng/building-detect/images/9063.jpg 186 | /data/feng/building-detect/images/9112.jpg 187 | /data/feng/building-detect/images/11630.jpg 188 | /data/feng/building-detect/images/14532.jpg 189 | /data/feng/building-detect/images/14192.jpg 190 | /data/feng/building-detect/images/14809.jpg 191 | /data/feng/building-detect/images/14414.jpg 192 | /data/feng/building-detect/images/4962.jpg 193 | /data/feng/building-detect/images/5515.jpg 194 | /data/feng/building-detect/images/7447.jpg 195 | /data/feng/building-detect/images/5686.jpg 196 | /data/feng/building-detect/images/14289.jpg 197 | /data/feng/building-detect/images/2084.jpg 198 | /data/feng/building-detect/images/13193.jpg 199 | /data/feng/building-detect/images/11506.jpg 200 | /data/feng/building-detect/images/12216.jpg 201 | /data/feng/building-detect/images/14311.jpg 202 | /data/feng/building-detect/images/4543.jpg 203 | /data/feng/building-detect/images/10846.jpg 204 | /data/feng/building-detect/images/12722.jpg 205 | /data/feng/building-detect/images/8275.jpg 206 | /data/feng/building-detect/images/6025.jpg 207 | /data/feng/building-detect/images/2238.jpg 208 | /data/feng/building-detect/images/7614.jpg 209 | /data/feng/building-detect/images/13651.jpg 210 | /data/feng/building-detect/images/5354.jpg 211 | /data/feng/building-detect/images/2400.jpg 212 | /data/feng/building-detect/images/13673.jpg 213 | /data/feng/building-detect/images/7973.jpg 214 | /data/feng/building-detect/images/7757.jpg 215 | /data/feng/building-detect/images/6220.jpg 216 | /data/feng/building-detect/images/3244.jpg 217 | /data/feng/building-detect/images/8841.jpg 218 | /data/feng/building-detect/images/4366.jpg 219 | /data/feng/building-detect/images/13887.jpg 220 | /data/feng/building-detect/images/8579.jpg 221 | /data/feng/building-detect/images/3292.jpg 222 | /data/feng/building-detect/images/9910.jpg 223 | /data/feng/building-detect/images/13524.jpg 224 | /data/feng/building-detect/images/6473.jpg 225 | /data/feng/building-detect/images/2834.jpg 226 | /data/feng/building-detect/images/6242.jpg 227 | /data/feng/building-detect/images/3641.jpg 228 | /data/feng/building-detect/images/6827.jpg 229 | /data/feng/building-detect/images/14340.jpg 230 | /data/feng/building-detect/images/5211.jpg 231 | /data/feng/building-detect/images/4281.jpg 232 | /data/feng/building-detect/images/1038.jpg 233 | /data/feng/building-detect/images/10083.jpg 234 | /data/feng/building-detect/images/7927.jpg 235 | /data/feng/building-detect/images/4483.jpg 236 | /data/feng/building-detect/images/5642.jpg 237 | /data/feng/building-detect/images/14125.jpg 238 | /data/feng/building-detect/images/8998.jpg 239 | /data/feng/building-detect/images/14997.jpg 240 | /data/feng/building-detect/images/3649.jpg 241 | /data/feng/building-detect/images/1733.jpg 242 | /data/feng/building-detect/images/14428.jpg 243 | /data/feng/building-detect/images/8249.jpg 244 | /data/feng/building-detect/images/5625.jpg 245 | /data/feng/building-detect/images/13363.jpg 246 | /data/feng/building-detect/images/1462.jpg 247 | /data/feng/building-detect/images/1975.jpg 248 | /data/feng/building-detect/images/917.jpg 249 | /data/feng/building-detect/images/6326.jpg 250 | /data/feng/building-detect/images/10550.jpg 251 | /data/feng/building-detect/images/11023.jpg 252 | /data/feng/building-detect/images/6565.jpg 253 | /data/feng/building-detect/images/2728.jpg 254 | /data/feng/building-detect/images/8227.jpg 255 | /data/feng/building-detect/images/12611.jpg 256 | /data/feng/building-detect/images/932.jpg 257 | /data/feng/building-detect/images/7768.jpg 258 | /data/feng/building-detect/images/1211.jpg 259 | /data/feng/building-detect/images/8432.jpg 260 | /data/feng/building-detect/images/2511.jpg 261 | /data/feng/building-detect/images/14144.jpg 262 | /data/feng/building-detect/images/1362.jpg 263 | /data/feng/building-detect/images/8359.jpg 264 | /data/feng/building-detect/images/2402.jpg 265 | /data/feng/building-detect/images/13191.jpg 266 | /data/feng/building-detect/images/7875.jpg 267 | /data/feng/building-detect/images/11467.jpg 268 | /data/feng/building-detect/images/8201.jpg 269 | /data/feng/building-detect/images/10675.jpg 270 | /data/feng/building-detect/images/879.jpg 271 | /data/feng/building-detect/images/5152.jpg 272 | /data/feng/building-detect/images/11638.jpg 273 | /data/feng/building-detect/images/3056.jpg 274 | /data/feng/building-detect/images/4114.jpg 275 | /data/feng/building-detect/images/6932.jpg 276 | /data/feng/building-detect/images/12598.jpg 277 | /data/feng/building-detect/images/1886.jpg 278 | /data/feng/building-detect/images/7704.jpg 279 | /data/feng/building-detect/images/1431.jpg 280 | /data/feng/building-detect/images/8411.jpg 281 | /data/feng/building-detect/images/11854.jpg 282 | /data/feng/building-detect/images/13119.jpg 283 | /data/feng/building-detect/images/104.jpg 284 | /data/feng/building-detect/images/12184.jpg 285 | /data/feng/building-detect/images/12889.jpg 286 | /data/feng/building-detect/images/12188.jpg 287 | /data/feng/building-detect/images/3305.jpg 288 | /data/feng/building-detect/images/7746.jpg 289 | /data/feng/building-detect/images/6292.jpg 290 | /data/feng/building-detect/images/5853.jpg 291 | /data/feng/building-detect/images/12511.jpg 292 | /data/feng/building-detect/images/2317.jpg 293 | /data/feng/building-detect/images/14459.jpg 294 | /data/feng/building-detect/images/8309.jpg 295 | /data/feng/building-detect/images/8543.jpg 296 | /data/feng/building-detect/images/1593.jpg 297 | /data/feng/building-detect/images/6541.jpg 298 | /data/feng/building-detect/images/13758.jpg 299 | /data/feng/building-detect/images/12785.jpg 300 | /data/feng/building-detect/images/12161.jpg 301 | /data/feng/building-detect/images/10452.jpg 302 | /data/feng/building-detect/images/7611.jpg 303 | /data/feng/building-detect/images/4053.jpg 304 | /data/feng/building-detect/images/7741.jpg 305 | /data/feng/building-detect/images/2865.jpg 306 | /data/feng/building-detect/images/9238.jpg 307 | /data/feng/building-detect/images/14155.jpg 308 | /data/feng/building-detect/images/6407.jpg 309 | /data/feng/building-detect/images/14819.jpg 310 | /data/feng/building-detect/images/7545.jpg 311 | /data/feng/building-detect/images/401.jpg 312 | /data/feng/building-detect/images/9096.jpg 313 | /data/feng/building-detect/images/6336.jpg 314 | /data/feng/building-detect/images/3875.jpg 315 | /data/feng/building-detect/images/6647.jpg 316 | /data/feng/building-detect/images/12326.jpg 317 | /data/feng/building-detect/images/10034.jpg 318 | /data/feng/building-detect/images/4302.jpg 319 | /data/feng/building-detect/images/15219.jpg 320 | /data/feng/building-detect/images/11400.jpg 321 | /data/feng/building-detect/images/5649.jpg 322 | /data/feng/building-detect/images/11346.jpg 323 | /data/feng/building-detect/images/9493.jpg 324 | /data/feng/building-detect/images/5003.jpg 325 | /data/feng/building-detect/images/3850.jpg 326 | /data/feng/building-detect/images/13342.jpg 327 | /data/feng/building-detect/images/9328.jpg 328 | /data/feng/building-detect/images/13452.jpg 329 | /data/feng/building-detect/images/6318.jpg 330 | /data/feng/building-detect/images/10753.jpg 331 | /data/feng/building-detect/images/11626.jpg 332 | /data/feng/building-detect/images/12492.jpg 333 | /data/feng/building-detect/images/1445.jpg 334 | /data/feng/building-detect/images/12944.jpg 335 | /data/feng/building-detect/images/5617.jpg 336 | /data/feng/building-detect/images/1984.jpg 337 | /data/feng/building-detect/images/4529.jpg 338 | /data/feng/building-detect/images/14468.jpg 339 | /data/feng/building-detect/images/13799.jpg 340 | /data/feng/building-detect/images/13548.jpg 341 | /data/feng/building-detect/images/14375.jpg 342 | /data/feng/building-detect/images/5976.jpg 343 | /data/feng/building-detect/images/14767.jpg 344 | /data/feng/building-detect/images/10548.jpg 345 | /data/feng/building-detect/images/2253.jpg 346 | /data/feng/building-detect/images/5627.jpg 347 | /data/feng/building-detect/images/7439.jpg 348 | /data/feng/building-detect/images/14458.jpg 349 | /data/feng/building-detect/images/613.jpg 350 | /data/feng/building-detect/images/12376.jpg 351 | /data/feng/building-detect/images/2876.jpg 352 | /data/feng/building-detect/images/4306.jpg 353 | /data/feng/building-detect/images/3510.jpg 354 | /data/feng/building-detect/images/7622.jpg 355 | /data/feng/building-detect/images/3648.jpg 356 | /data/feng/building-detect/images/8385.jpg 357 | /data/feng/building-detect/images/11308.jpg 358 | /data/feng/building-detect/images/12870.jpg 359 | /data/feng/building-detect/images/2441.jpg 360 | /data/feng/building-detect/images/11128.jpg 361 | /data/feng/building-detect/images/8465.jpg 362 | /data/feng/building-detect/images/1874.jpg 363 | /data/feng/building-detect/images/1845.jpg 364 | /data/feng/building-detect/images/14420.jpg 365 | /data/feng/building-detect/images/229.jpg 366 | /data/feng/building-detect/images/9026.jpg 367 | /data/feng/building-detect/images/4174.jpg 368 | /data/feng/building-detect/images/14256.jpg 369 | /data/feng/building-detect/images/8894.jpg 370 | /data/feng/building-detect/images/14803.jpg 371 | /data/feng/building-detect/images/207.jpg 372 | /data/feng/building-detect/images/6098.jpg 373 | /data/feng/building-detect/images/11636.jpg 374 | /data/feng/building-detect/images/14750.jpg 375 | /data/feng/building-detect/images/6615.jpg 376 | /data/feng/building-detect/images/8549.jpg 377 | /data/feng/building-detect/images/2330.jpg 378 | /data/feng/building-detect/images/3973.jpg 379 | /data/feng/building-detect/images/13757.jpg 380 | /data/feng/building-detect/images/7928.jpg 381 | /data/feng/building-detect/images/758.jpg 382 | /data/feng/building-detect/images/775.jpg 383 | /data/feng/building-detect/images/12478.jpg 384 | /data/feng/building-detect/images/4367.jpg 385 | /data/feng/building-detect/images/4793.jpg 386 | /data/feng/building-detect/images/7405.jpg 387 | /data/feng/building-detect/images/12672.jpg 388 | /data/feng/building-detect/images/9331.jpg 389 | /data/feng/building-detect/images/385.jpg 390 | /data/feng/building-detect/images/13851.jpg 391 | /data/feng/building-detect/images/3962.jpg 392 | /data/feng/building-detect/images/13592.jpg 393 | /data/feng/building-detect/images/8100.jpg 394 | /data/feng/building-detect/images/10679.jpg 395 | /data/feng/building-detect/images/9349.jpg 396 | /data/feng/building-detect/images/13255.jpg 397 | /data/feng/building-detect/images/11998.jpg 398 | /data/feng/building-detect/images/12851.jpg 399 | /data/feng/building-detect/images/12630.jpg 400 | /data/feng/building-detect/images/10154.jpg 401 | /data/feng/building-detect/images/1994.jpg 402 | /data/feng/building-detect/images/14779.jpg 403 | /data/feng/building-detect/images/4009.jpg 404 | /data/feng/building-detect/images/6601.jpg 405 | /data/feng/building-detect/images/1659.jpg 406 | /data/feng/building-detect/images/8134.jpg 407 | /data/feng/building-detect/images/4850.jpg 408 | /data/feng/building-detect/images/12398.jpg 409 | /data/feng/building-detect/images/6802.jpg 410 | /data/feng/building-detect/images/5772.jpg 411 | /data/feng/building-detect/images/10170.jpg 412 | /data/feng/building-detect/images/8370.jpg 413 | /data/feng/building-detect/images/12296.jpg 414 | /data/feng/building-detect/images/14453.jpg 415 | /data/feng/building-detect/images/15153.jpg 416 | /data/feng/building-detect/images/6303.jpg 417 | /data/feng/building-detect/images/645.jpg 418 | /data/feng/building-detect/images/3903.jpg 419 | /data/feng/building-detect/images/7813.jpg 420 | /data/feng/building-detect/images/5949.jpg 421 | /data/feng/building-detect/images/8847.jpg 422 | /data/feng/building-detect/images/5825.jpg 423 | /data/feng/building-detect/images/12982.jpg 424 | /data/feng/building-detect/images/8273.jpg 425 | /data/feng/building-detect/images/8867.jpg 426 | /data/feng/building-detect/images/10686.jpg 427 | /data/feng/building-detect/images/4370.jpg 428 | /data/feng/building-detect/images/14927.jpg 429 | /data/feng/building-detect/images/13660.jpg 430 | /data/feng/building-detect/images/1021.jpg 431 | /data/feng/building-detect/images/14417.jpg 432 | /data/feng/building-detect/images/1383.jpg 433 | /data/feng/building-detect/images/9487.jpg 434 | -------------------------------------------------------------------------------- /new_detection/dataset.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from torch.utils.data import Dataset 3 | import torchvision.transforms as transforms 4 | from PIL import Image 5 | import json 6 | import pdb 7 | 8 | class BuildingDetectionDataset(Dataset): 9 | """Dataset for loading images and annotations from a config file. 10 | Each line contains information for both the image and annotation. 11 | E.g., '/data/feng/building-detect/images/1225.jpg' is the image path, 12 | and the corresponding annotation path is '/data/feng/building-detect/annotations/1225.json' 13 | 14 | The class is designed specifically to work with torchvision.models.detection.faster_rcnn. 15 | Check the output from __getitem__ to understand the specific data format. 16 | """ 17 | def __init__(self, config_file, transform=transforms.ToTensor()): 18 | """ 19 | Args: 20 | config_file (string): path to config file of all data, each line 21 | consists of an image path 22 | transform (callable, optional): Optional transform to be applied 23 | on a sample. 24 | """ 25 | with open(config_file, 'r') as file: 26 | self.img_paths = file.readlines() 27 | self.label_paths = [path.replace('images', 'annotations').replace('.jpg', '.json') for path in self.img_paths] 28 | self.transform = transform 29 | 30 | def __len__(self): 31 | return len(self.img_paths) 32 | 33 | def __getitem__(self, idx): 34 | # Load image 35 | img_path = self.img_paths[idx].rstrip() 36 | img = Image.open(img_path) 37 | if self.transform: 38 | img = self.transform(img) 39 | 40 | # Load annotation 41 | label_path = self.label_paths[idx].rstrip() 42 | with open(label_path, 'r') as f: 43 | # [{class: 0/1, bbox: [x,y,w,h]}, {class, bbox}, ...] 44 | raw_labels = json.load(f) 45 | boxes = [] 46 | labels = [] 47 | channel, img_w, img_h = img.shape 48 | for raw_label in raw_labels: 49 | # [x, y, w, h], normalized 50 | bbox = raw_label['bbox'] 51 | x1 = bbox[0]*img_w 52 | y1 = bbox[1]*img_h 53 | x2 = (bbox[0]+bbox[2])*img_w 54 | y2 = (bbox[1]+bbox[3])*img_h 55 | # [x1, y1, x2, y2], image-sized 56 | boxes.append([x1, y1, x2, y2]) 57 | labels.append(raw_label['class']) 58 | 59 | target = { 60 | "boxes": torch.FloatTensor(boxes), 61 | "labels": torch.LongTensor(labels), 62 | "area": torch.LongTensor(0), 63 | "iscrowd": torch.LongTensor(0) 64 | } 65 | 66 | return img, target 67 | 68 | def custom_collate_fn(batch): 69 | data = [item[0] for item in batch] 70 | target = [item[1] for item in batch] 71 | return (data, target) 72 | 73 | # dataset = BuildingDetectionDataset('config/train_config.txt') 74 | # for (img, target) in dataset: 75 | # pdb.set_trace() 76 | 77 | -------------------------------------------------------------------------------- /new_detection/eval.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from utils import * 3 | from model import fasterrcnn_resnet18_fpn 4 | from torch.utils.data import DataLoader 5 | from dataset import BuildingDetectionDataset, custom_collate_fn 6 | import torchvision.transforms as transforms 7 | import json 8 | import pdb 9 | 10 | # Output structure: 11 | # building_id: unique 12 | # region: Henderson 13 | # label: residential/non-residential 14 | # prediction region: loop over all prediction to calculate this 15 | # label region: 16 | # IoU: intersection over union 17 | # residential likelihood: P 18 | # non-residential likelihood: 1 - P 19 | 20 | def find_best_box(target, preds, iou_threshold): 21 | best_pred = -1 22 | for pred_idx, pred in enumerate(preds): 23 | iou = calculate_iou(target, pred).item() 24 | if iou > iou_threshold: 25 | best_pred = pred_idx 26 | return best_pred 27 | 28 | def calculate_iou(target, pred): 29 | # target/pred: tensor[x1, y1, x2, y2] 30 | # 1 x 4 31 | target_tensor = target.unsqueeze(0) 32 | pred_tensor = pred.unsqueeze(0) 33 | iou = find_jaccard_overlap(target_tensor, pred_tensor) 34 | return iou 35 | 36 | data_dir = '/data/feng/building-detect/' 37 | pretrained_weight = 'checkpoints/12_14.pth.tar' 38 | device = torch.device('cuda:2') 39 | batch_size = 10 40 | eval_size = 5000 41 | iou_threshold = 0.2 42 | 43 | model = fasterrcnn_resnet18_fpn(num_classes=2, pretrained_backbone=True) 44 | model.load_state_dict(torch.load(pretrained_weight)) 45 | model.to(device) 46 | model.eval() 47 | 48 | val_loader = DataLoader(BuildingDetectionDataset( 49 | '/home/yuansong/code/building/new_detection/config/test_config.txt', 50 | transforms.Compose([ 51 | transforms.Resize((224, 224)), 52 | transforms.ToTensor(), 53 | transforms.Normalize(mean=[0.485, 0.456, 0.406], 54 | std=[0.229, 0.224, 0.225]) 55 | ])),batch_size=batch_size, shuffle=False, pin_memory=False, 56 | collate_fn=custom_collate_fn 57 | ) 58 | results = [] 59 | building_id = 0 60 | for batch_idx, (inputs, targets) in enumerate(val_loader): 61 | # [N x (C x W x H)] 62 | inputs = [input_.to(device) for input_ in inputs] 63 | # [N x {boxes, labels, area, iscrowd}] 64 | targets = [{k: v.to(device) for k, v in t.items()} for t in targets] 65 | outputs = model(inputs) 66 | for target_idx, target in enumerate(targets): 67 | for building_idx, gt_box in enumerate(target['boxes']): 68 | pred_box_idx = find_best_box(gt_box, outputs[target_idx]['boxes'].detach(), iou_threshold) 69 | if pred_box_idx == -1: 70 | pred_box = torch.FloatTensor([]) 71 | iou = 0 72 | res_prob = -1 73 | non_res_prob = -1 74 | else: 75 | pred_box = outputs[target_idx]['boxes'][pred_box_idx].detach() 76 | iou = calculate_iou(gt_box, pred_box).item() 77 | res_prob = outputs[target_idx]['scores'][pred_box_idx].item() 78 | non_res_prob = 1 - res_prob 79 | label = target['labels'][building_idx].item() 80 | building_result = { 81 | "building_id": building_id, 82 | "region": "Henderson", 83 | "groundtruth label": label, 84 | "prediction box": pred_box.tolist(), 85 | "groundtruth box": gt_box.detach().tolist(), 86 | "IoU": iou, 87 | "residential likelihood": res_prob, 88 | "non-residential likelihood": non_res_prob, 89 | } 90 | results.append(building_result) 91 | building_id += 1 92 | print(building_id) 93 | if building_id >= eval_size: 94 | break 95 | with open('eval_result.json', 'w') as f: 96 | json.dump(results, f) 97 | print('evaluation results are dumped to eval_result.json') -------------------------------------------------------------------------------- /new_detection/model.py: -------------------------------------------------------------------------------- 1 | from torchvision.models.detection.faster_rcnn import FasterRCNN 2 | from torchvision.models.detection.backbone_utils import resnet_fpn_backbone 3 | import torch.nn as nn 4 | import pdb 5 | 6 | def fasterrcnn_resnet18_fpn(num_classes=2, pretrained_backbone=True, **kwargs): 7 | """ 8 | Constructs a Faster R-CNN model with a ResNet-18-FPN backbone. 9 | The input to the model is expected to be a list of tensors, each of shape ``[C, H, W]``, one for each 10 | image, and should be in ``0-1`` range. Different images can have different sizes. 11 | The behavior of the model changes depending if it is in training or evaluation mode. 12 | During training, the model expects both the input tensors, as well as a targets (list of dictionary), 13 | containing: 14 | - boxes (``FloatTensor[N, 4]``): the ground-truth boxes in ``[x1, y1, x2, y2]`` format, with values 15 | between ``0`` and ``H`` and ``0`` and ``W`` 16 | - labels (``Int64Tensor[N]``): the class label for each ground-truth box 17 | The model returns a ``Dict[Tensor]`` during training, containing the classification and regression 18 | losses for both the RPN and the R-CNN. 19 | During inference, the model requires only the input tensors, and returns the post-processed 20 | predictions as a ``List[Dict[Tensor]]``, one for each input image. The fields of the ``Dict`` are as 21 | follows: 22 | - boxes (``FloatTensor[N, 4]``): the predicted boxes in ``[x1, y1, x2, y2]`` format, with values between 23 | ``0`` and ``H`` and ``0`` and ``W`` 24 | - labels (``Int64Tensor[N]``): the predicted labels for each image 25 | - scores (``Tensor[N]``): the scores or each prediction 26 | Example:: 27 | >>> model = torchvision.models.detection.fasterrcnn_resnet50_fpn(pretrained=True) 28 | >>> model.eval() 29 | >>> x = [torch.rand(3, 300, 400), torch.rand(3, 500, 400)] 30 | >>> predictions = model(x) 31 | """ 32 | backbone = resnet_fpn_backbone('resnet18', pretrained_backbone) 33 | model = FasterRCNN(backbone, num_classes, **kwargs) 34 | # Modifications make the model smaller -- lessen overfitting 35 | # model.backbone.body.layer3 = nn.Sequential() 36 | # model.backbone.body.layer4 = nn.Sequential() 37 | # model.backbone.fpn.inner_blocks[1] = nn.Conv2d(128, 256, kernel_size=(1, 1), stride=(1, 1)) 38 | # model.backbone.fpn.inner_blocks[2] = nn.Conv2d(128, 256, kernel_size=(1, 1), stride=(1, 1)) 39 | # model.backbone.fpn.inner_blocks[3] = nn.Conv2d(128, 256, kernel_size=(1, 1), stride=(1, 1)) 40 | # model.backbone.fpn.layer_blocks[0] = nn.Conv2d(256, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) 41 | # model.backbone.fpn.layer_blocks[1] = nn.Conv2d(256, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) 42 | # model.backbone.fpn.layer_blocks[2] = nn.Conv2d(256, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) 43 | # model.backbone.fpn.layer_blocks[3] = nn.Conv2d(256, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) 44 | # model.rpn.head.conv = nn.Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) 45 | # model.rpn.head.cls_logits = nn.Conv2d(128, 3, kernel_size=(1, 1), stride=(1, 1)) 46 | # model.rpn.head.bbox_pred = nn.Conv2d(128, 12, kernel_size=(1, 1), stride=(1, 1)) 47 | # model.rpn.conv = nn.Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)) 48 | # model.rpn.cls_logits = nn.Conv2d(128, 3, kernel_size=(1, 1), stride=(1, 1)) 49 | # model.rpn.bbox_pred = nn.Conv2d(128, 12, kernel_size=(1, 1), stride=(1, 1)) 50 | # model.roi_heads.box_head.fc6 = nn.Linear(in_features=6272, out_features=256, bias=True) 51 | # model.roi_heads.box_head.fc7 = nn.Linear(in_features=256, out_features=256, bias=True) 52 | # model.roi_heads.box_predictor.cls_score = nn.Linear(in_features=256, out_features=2, bias=True) 53 | # model.roi_heads.box_predictor.bbox_pred = nn.Linear(in_features=256, out_features=8, bias=True) 54 | return model -------------------------------------------------------------------------------- /new_detection/train.py: -------------------------------------------------------------------------------- 1 | # Training script to detect and classify residential buildings 2 | # on satellite images. 3 | import os 4 | import matplotlib 5 | matplotlib.use('Agg') 6 | import matplotlib.pyplot as plt 7 | import torch 8 | import torch.nn as nn 9 | import torchvision.transforms as transforms 10 | import torch.optim as optim 11 | from torch.utils.data import DataLoader 12 | import torchnet.meter as meter 13 | from torch.utils.tensorboard import SummaryWriter 14 | import cv2 15 | from dataset import BuildingDetectionDataset, custom_collate_fn 16 | from utils import * 17 | from model import fasterrcnn_resnet18_fpn 18 | from datetime import datetime 19 | import time 20 | import pdb 21 | 22 | def get_loss(model, inputs, targets, optimizer, backward=True): 23 | model.train() 24 | loss_dict = model(inputs, targets) 25 | loss = sum(los for los in loss_dict.values()) 26 | if backward: 27 | optimizer.zero_grad() 28 | loss.backward() 29 | optimizer.step() 30 | return loss.item() 31 | 32 | def get_acc(model, inputs, targets): 33 | model.eval() 34 | outputs = model(inputs) 35 | cpu_device = torch.device('cpu') 36 | mAP = calculate_metric(outputs, targets, device=cpu_device) 37 | return mAP, outputs 38 | 39 | def train_or_eval(model, dataloader, optimizer=None, train=True, device=torch.device('cuda:0'), store=False): 40 | acc_meter = meter.AverageValueMeter() 41 | loss_meter = meter.AverageValueMeter() 42 | for batch_idx, (inputs, targets) in enumerate(dataloader): 43 | start_time = time.time() 44 | # [N x (C x W x H)] 45 | inputs = [input_.to(device) for input_ in inputs] 46 | # [N x {boxes, labels, area, iscrowd}] 47 | targets = [{k: v.to(device) for k, v in t.items()} for t in targets] 48 | mAP, preds = get_acc(model, inputs, targets) 49 | acc_meter.add(mAP) 50 | if store: 51 | output_annotated_images(inputs, targets) 52 | loss = get_loss(model, inputs, targets, optimizer, backward=train) 53 | loss_meter.add(loss) 54 | if batch_idx % 10 == 0: 55 | tag = 'train' if train else 'val' 56 | curr_time = datetime.now().strftime("%Y-%m-%d %H:%M") 57 | delta_time = (time.time() - start_time) * 120 58 | print('%s %s batch: %i loss: %f acc: %f epoch time: %f' % (curr_time, tag, batch_idx, loss_meter.mean, acc_meter.mean, delta_time)) 59 | if (not train) and batch_idx == 100: 60 | return loss_meter.mean, acc_meter.mean 61 | if batch_idx == 500: 62 | return loss_meter.mean, acc_meter.mean 63 | return loss_meter.mean, acc_meter.mean 64 | 65 | # predictions and targets are both torch tensors 66 | def calculate_metric(predictions, targets, device=torch.device('cpu')): 67 | ''' 68 | predictions/targets: [{ 69 | boxes: [[x1, y1, x2, y2], ...], 70 | labels: [0/1, ...], 71 | scores: [0.53, 0.23, ...] 72 | }, ...] 73 | ''' 74 | average_precisions, mean_average_precision = calculate_mAP( 75 | det_boxes=[p['boxes'] for p in predictions], 76 | det_labels=[p['labels'] for p in predictions], 77 | det_scores=[p['scores'] for p in predictions], 78 | true_boxes=[t['boxes'] for t in targets], 79 | true_labels=[t['labels'] for t in targets], 80 | true_difficulties=[torch.IntTensor([0 for l in t['labels']]) for t in targets], 81 | device=device 82 | ) 83 | return mean_average_precision 84 | 85 | def output_history_graph(train_hist, val_hist): 86 | epochs = len(train_hist) 87 | plt.figure(0) 88 | plt.plot(list(range(epochs)), [x[0] for x in train_hist], label='train') 89 | plt.plot(list(range(epochs)), [x[0] for x in val_hist], label='val') 90 | plt.legend(loc='upper left') 91 | plt.savefig('loss.jpg') 92 | plt.clf() 93 | 94 | plt.figure(1) 95 | plt.plot(list(range(epochs)), [x[1] for x in train_hist], label='train') 96 | plt.plot(list(range(epochs)), [x[1] for x in val_hist], label='val') 97 | plt.legend(loc='upper left') 98 | plt.savefig('acc.jpg') 99 | plt.clf() 100 | 101 | # parameters 102 | data_dir = '/data/feng/building-detect/' 103 | checkpoint_dir = 'checkpoints' 104 | lr = 3e-4 105 | batch_size = 16 106 | num_epochs = 500 107 | pretrained_weight = 'checkpoints/best_acc.pth.tar' 108 | device = torch.device('cuda:1') 109 | 110 | def count_parameters(model): 111 | return sum(p.numel() for p in model.parameters() if p.requires_grad) 112 | 113 | # load model 114 | model = fasterrcnn_resnet18_fpn(num_classes=2, pretrained_backbone=True) 115 | # model.load_state_dict(torch.load(pretrained_weight)) 116 | model.to(device) 117 | # define data transform and data loader 118 | train_loader = DataLoader(BuildingDetectionDataset( 119 | '/home/yuansong/code/building/new_detection/config/train_config.txt', 120 | transforms.Compose([ 121 | transforms.Resize((224, 224)), 122 | transforms.ToTensor(), 123 | transforms.Normalize(mean=[0.485, 0.456, 0.406], 124 | std=[0.229, 0.224, 0.225]) 125 | ])), batch_size=batch_size, shuffle=True, pin_memory=False, 126 | collate_fn=custom_collate_fn 127 | ) 128 | val_loader = DataLoader(BuildingDetectionDataset( 129 | '/home/yuansong/code/building/new_detection/config/test_config.txt', 130 | transforms.Compose([ 131 | transforms.Resize((224, 224)), 132 | transforms.ToTensor(), 133 | transforms.Normalize(mean=[0.485, 0.456, 0.406], 134 | std=[0.229, 0.224, 0.225]) 135 | ])),batch_size=batch_size, shuffle=False, pin_memory=False, 136 | collate_fn=custom_collate_fn 137 | ) 138 | 139 | optimizer = optim.Adam(model.parameters(), lr=lr) 140 | 141 | # training loop 142 | train_hist = [] 143 | val_hist = [] 144 | best_acc = 0.0 145 | for epoch in range(num_epochs): 146 | train_loss, train_acc = train_or_eval(model, train_loader, optimizer, train=True, device=device, store=False) 147 | train_hist.append([train_loss, train_acc]) 148 | val_loss, val_acc = train_or_eval(model, val_loader, train=False, device=device, store=False) 149 | val_hist.append([val_loss, val_acc]) 150 | 151 | if val_acc > best_acc: 152 | save_path = os.path.join(checkpoint_dir, 'best_acc.pth.tar') 153 | torch.save(model.state_dict(), save_path) 154 | best_acc = val_acc 155 | print('model with val accuracy %f saved to path %s' % (val_acc, save_path)) 156 | 157 | print('****** epoch: %i train loss: %f train acc: %f val loss: %f val acc: %f best_acc: %f ******' % (epoch, train_loss, train_acc, val_loss, val_acc, best_acc)) 158 | output_history_graph(train_hist, val_hist) 159 | -------------------------------------------------------------------------------- /new_detection/utils.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import pdb 3 | import cv2 4 | import os 5 | import numpy as np 6 | 7 | def tensor_memory(tensor): 8 | return tensor.element_size() * tensor.nelement() / 1e6 9 | 10 | def _normalize(img): 11 | img = img - np.min(img) 12 | img = img / np.max(img) 13 | img = np.uint8(255 * img) 14 | return img 15 | 16 | def output_annotated_images(images, annotations, output_dir='output'): 17 | """ 18 | Args 19 | images: [N x (C x W x H)] 20 | annotations: [N x {boxes[[x1, y1, x2, y2], ...], labels[0/1, ...], ...}] 21 | """ 22 | for idx, image in enumerate(images): 23 | image = image.cpu().numpy() 24 | image = _normalize(image) 25 | image = np.moveaxis(image, 0, -1).copy() 26 | boxes = annotations[idx]['boxes'].cpu().detach().numpy() 27 | labels = annotations[idx]['labels'].cpu().numpy() 28 | for b, box in enumerate(boxes): 29 | x1 = box[0] 30 | y1 = box[1] 31 | x2 = box[2] 32 | y2 = box[3] 33 | l = labels[b] 34 | color = (255,0,0) if l == 1 else (0,255,0) 35 | cv2.rectangle(image, (x1, y1), (x2, y2), color, 1) 36 | # print(box) 37 | cv2.imwrite(os.path.join(output_dir, str(idx)+'.jpg'), image) 38 | print('image outputted to %s' % os.path.join(output_dir, str(idx)+'.jpg')) 39 | 40 | 41 | def calculate_mAP(det_boxes, det_labels, det_scores, true_boxes, true_labels, true_difficulties, device): 42 | """ 43 | Calculate the Mean Average Precision (mAP) of detected objects. 44 | See https://medium.com/@jonathan_hui/map-mean-average-precision-for-object-detection-45c121a31173 for an explanation 45 | :param det_boxes: list of tensors, one tensor for each image containing detected objects' bounding boxes 46 | :param det_labels: list of tensors, one tensor for each image containing detected objects' labels 47 | :param det_scores: list of tensors, one tensor for each image containing detected objects' labels' scores 48 | :param true_boxes: list of tensors, one tensor for each image containing actual objects' bounding boxes 49 | :param true_labels: list of tensors, one tensor for each image containing actual objects' labels 50 | :param true_difficulties: list of tensors, one tensor for each image containing actual objects' difficulty (0 or 1) 51 | :return: list of average precisions for all classes, mean average precision (mAP) 52 | """ 53 | # pdb.set_trace() 54 | voc_labels = ('non-residential', 'residential') 55 | label_map = {k: v + 1 for v, k in enumerate(voc_labels)} 56 | label_map['background'] = 0 57 | rev_label_map = {v: k for k, v in label_map.items()} # Inverse mapping 58 | 59 | assert len(det_boxes) == len(det_labels) == len(det_scores) == len(true_boxes) == len( 60 | true_labels) == len( 61 | true_difficulties) # these are all lists of tensors of the same length, i.e. number of images 62 | n_classes = len(label_map) 63 | 64 | # Store all (true) objects in a single continuous tensor while keeping track of the image it is from 65 | true_images = list() 66 | for i in range(len(true_labels)): 67 | true_images.extend([i] * true_labels[i].size(0)) 68 | true_images = torch.LongTensor(true_images).to( 69 | device) # (n_objects), n_objects is the total no. of objects across all images 70 | true_boxes = torch.cat(true_boxes, dim=0) # (n_objects, 4) 71 | true_labels = torch.cat(true_labels, dim=0) # (n_objects) 72 | true_difficulties = torch.cat(true_difficulties, dim=0) # (n_objects) 73 | 74 | assert true_images.size(0) == true_boxes.size(0) == true_labels.size(0) 75 | 76 | # Store all detections in a single continuous tensor while keeping track of the image it is from 77 | det_images = list() 78 | for i in range(len(det_labels)): 79 | det_images.extend([i] * det_labels[i].size(0)) 80 | det_images = torch.LongTensor(det_images).to(device) # (n_detections) 81 | det_boxes = torch.cat(det_boxes, dim=0) # (n_detections, 4) 82 | det_labels = torch.cat(det_labels, dim=0) # (n_detections) 83 | det_scores = torch.cat(det_scores, dim=0) # (n_detections) 84 | 85 | assert det_images.size(0) == det_boxes.size(0) == det_labels.size(0) == det_scores.size(0) 86 | 87 | # Calculate APs for each class (except background) 88 | average_precisions = torch.zeros((n_classes - 1), dtype=torch.float) # (n_classes - 1) 89 | for c in range(1, n_classes): 90 | # Extract only objects with this class 91 | true_class_images = true_images[true_labels == c] # (n_class_objects) 92 | true_class_boxes = true_boxes[true_labels == c] # (n_class_objects, 4) 93 | true_class_difficulties = true_difficulties[true_labels == c] # (n_class_objects) 94 | n_easy_class_objects = (1 - true_class_difficulties).sum().item() # ignore difficult objects 95 | 96 | # Keep track of which true objects with this class have already been 'detected' 97 | # So far, none 98 | true_class_boxes_detected = torch.zeros((true_class_difficulties.size(0)), dtype=torch.uint8).to( 99 | device) # (n_class_objects) 100 | 101 | # Extract only detections with this class 102 | det_class_images = det_images[det_labels == c] # (n_class_detections) 103 | det_class_boxes = det_boxes[det_labels == c] # (n_class_detections, 4) 104 | det_class_scores = det_scores[det_labels == c] # (n_class_detections) 105 | n_class_detections = det_class_boxes.size(0) 106 | if n_class_detections == 0: 107 | continue 108 | 109 | # Sort detections in decreasing order of confidence/scores 110 | det_class_scores, sort_ind = torch.sort(det_class_scores, dim=0, descending=True) # (n_class_detections) 111 | det_class_images = det_class_images[sort_ind] # (n_class_detections) 112 | det_class_boxes = det_class_boxes[sort_ind] # (n_class_detections, 4) 113 | 114 | # In the order of decreasing scores, check if true or false positive 115 | true_positives = torch.zeros((n_class_detections), dtype=torch.float).to(device) # (n_class_detections) 116 | false_positives = torch.zeros((n_class_detections), dtype=torch.float).to(device) # (n_class_detections) 117 | for d in range(n_class_detections): 118 | this_detection_box = det_class_boxes[d].unsqueeze(0) # (1, 4) 119 | this_image = det_class_images[d] # (), scalar 120 | 121 | # Find objects in the same image with this class, their difficulties, and whether they have been detected before 122 | object_boxes = true_class_boxes[true_class_images == this_image] # (n_class_objects_in_img) 123 | object_difficulties = true_class_difficulties[true_class_images == this_image] # (n_class_objects_in_img) 124 | # If no such object in this image, then the detection is a false positive 125 | if object_boxes.size(0) == 0: 126 | false_positives[d] = 1 127 | continue 128 | 129 | # Find maximum overlap of this detection with objects in this image of this class 130 | overlaps = find_jaccard_overlap(this_detection_box, object_boxes) # (1, n_class_objects_in_img) 131 | max_overlap, ind = torch.max(overlaps.squeeze(0), dim=0) # (), () - scalars 132 | 133 | # 'ind' is the index of the object in these image-level tensors 'object_boxes', 'object_difficulties' 134 | # In the original class-level tensors 'true_class_boxes', etc., 'ind' corresponds to object with index... 135 | original_ind = torch.LongTensor(range(true_class_boxes.size(0)))[true_class_images == this_image][ind] 136 | # We need 'original_ind' to update 'true_class_boxes_detected' 137 | 138 | # If the maximum overlap is greater than the threshold of 0.5, it's a match 139 | if max_overlap.item() > 0.5: 140 | # If the object it matched with is 'difficult', ignore it 141 | if object_difficulties[ind] == 0: 142 | # If this object has already not been detected, it's a true positive 143 | if true_class_boxes_detected[original_ind] == 0: 144 | true_positives[d] = 1 145 | true_class_boxes_detected[original_ind] = 1 # this object has now been detected/accounted for 146 | # Otherwise, it's a false positive (since this object is already accounted for) 147 | else: 148 | false_positives[d] = 1 149 | # Otherwise, the detection occurs in a different location than the actual object, and is a false positive 150 | else: 151 | false_positives[d] = 1 152 | # pdb.set_trace() 153 | 154 | # Compute cumulative precision and recall at each detection in the order of decreasing scores 155 | cumul_true_positives = torch.cumsum(true_positives, dim=0) # (n_class_detections) 156 | cumul_false_positives = torch.cumsum(false_positives, dim=0) # (n_class_detections) 157 | cumul_precision = cumul_true_positives / ( 158 | cumul_true_positives + cumul_false_positives + 1e-10) # (n_class_detections) 159 | cumul_recall = cumul_true_positives / n_easy_class_objects # (n_class_detections) 160 | 161 | # Find the mean of the maximum of the precisions corresponding to recalls above the threshold 't' 162 | recall_thresholds = torch.arange(start=0, end=1.1, step=.1).tolist() # (11) 163 | precisions = torch.zeros((len(recall_thresholds)), dtype=torch.float).to(device) # (11) 164 | for i, t in enumerate(recall_thresholds): 165 | recalls_above_t = cumul_recall >= t 166 | if recalls_above_t.any(): 167 | precisions[i] = cumul_precision[recalls_above_t].max() 168 | else: 169 | precisions[i] = 0. 170 | average_precisions[c - 1] = precisions.mean() # c is in [1, n_classes - 1] 171 | # Calculate Mean Average Precision (mAP) 172 | mean_average_precision = average_precisions.mean().item() 173 | 174 | # Keep class-wise average precisions in a dictionary 175 | average_precisions = {rev_label_map[c + 1]: v for c, v in enumerate(average_precisions.tolist())} 176 | 177 | return average_precisions, mean_average_precision 178 | 179 | def find_jaccard_overlap(set_1, set_2): 180 | """ 181 | Find the Jaccard Overlap (IoU) of every box combination between two sets of boxes that are in boundary coordinates. 182 | :param set_1: set 1, a tensor of dimensions (n1, 4) 183 | :param set_2: set 2, a tensor of dimensions (n2, 4) 184 | :return: Jaccard Overlap of each of the boxes in set 1 with respect to each of the boxes in set 2, a tensor of dimensions (n1, n2) 185 | """ 186 | 187 | # Find intersections 188 | intersection = find_intersection(set_1, set_2) # (n1, n2) 189 | 190 | # Find areas of each box in both sets 191 | areas_set_1 = (set_1[:, 2] - set_1[:, 0]) * (set_1[:, 3] - set_1[:, 1]) # (n1) 192 | areas_set_2 = (set_2[:, 2] - set_2[:, 0]) * (set_2[:, 3] - set_2[:, 1]) # (n2) 193 | 194 | # Find the union 195 | # PyTorch auto-broadcasts singleton dimensions 196 | union = areas_set_1.unsqueeze(1) + areas_set_2.unsqueeze(0) - intersection # (n1, n2) 197 | 198 | return intersection / union # (n1, n2) 199 | 200 | def find_intersection(set_1, set_2): 201 | """ 202 | Find the intersection of every box combination between two sets of boxes that are in boundary coordinates. 203 | :param set_1: set 1, a tensor of dimensions (n1, 4) 204 | :param set_2: set 2, a tensor of dimensions (n2, 4) 205 | :return: intersection of each of the boxes in set 1 with respect to each of the boxes in set 2, a tensor of dimensions (n1, n2) 206 | """ 207 | 208 | # PyTorch auto-broadcasts singleton dimensions 209 | lower_bounds = torch.max(set_1[:, :2].unsqueeze(1), set_2[:, :2].unsqueeze(0)) # (n1, n2, 2) 210 | upper_bounds = torch.min(set_1[:, 2:].unsqueeze(1), set_2[:, 2:].unsqueeze(0)) # (n1, n2, 2) 211 | intersection_dims = torch.clamp(upper_bounds - lower_bounds, min=0) # (n1, n2, 2) 212 | return intersection_dims[:, :, 0] * intersection_dims[:, :, 1] # (n1, n2) 213 | 214 | # testing 215 | # det_boxes = [torch.FloatTensor([[2.2, 2.2, 4.2, 4.3]])] 216 | # det_labels = [torch.IntTensor([1])] 217 | # det_scores = [torch.IntTensor([0.8])] 218 | # true_boxes = [ 219 | # torch.FloatTensor([[1, 1, 3, 3], [2, 2, 4, 4]]) 220 | # ] 221 | # true_labels = [ 222 | # torch.IntTensor([0, 1]) 223 | # ] 224 | # true_difficulties = [ 225 | # torch.IntTensor([0, 0]) 226 | # ] 227 | # device = torch.device('cpu') 228 | # mAP = calculate_mAP(det_boxes, det_labels, det_scores, true_boxes, true_labels, true_difficulties, device) 229 | # pdb.set_trace() --------------------------------------------------------------------------------