├── EXTD_32.py ├── EXTD_48.py ├── EXTD_64.py ├── LICENSE ├── NOTICE ├── README.md ├── bbox_setup.py ├── build └── temp.linux-x86_64-3.5 │ └── eval_tools │ └── box_overlaps.o ├── data ├── config.py ├── egohand.py ├── face_train.txt ├── face_val.txt ├── factory.py ├── vochead.py └── widerface.py ├── demo.py ├── eval_tools ├── box_overlaps.c ├── box_overlaps.pyx ├── evaluation.py ├── ground_truth │ ├── wider_easy_val.mat │ ├── wider_face_val.mat │ ├── wider_hard_val.mat │ └── wider_medium_val.mat ├── plot │ ├── baselines │ │ ├── Test │ │ │ ├── setting_ext │ │ │ │ ├── acf │ │ │ │ │ ├── wider_pr_info_acf_easy.mat │ │ │ │ │ ├── wider_pr_info_acf_hard.mat │ │ │ │ │ └── wider_pr_info_acf_medium.mat │ │ │ │ ├── dpm │ │ │ │ │ ├── wider_pr_info_dpm_easy.mat │ │ │ │ │ ├── wider_pr_info_dpm_hard.mat │ │ │ │ │ └── wider_pr_info_dpm_medium.mat │ │ │ │ ├── faceness │ │ │ │ │ ├── wider_pr_info_faceness_easy.mat │ │ │ │ │ ├── wider_pr_info_faceness_hard.mat │ │ │ │ │ └── wider_pr_info_faceness_medium.mat │ │ │ │ └── vj │ │ │ │ │ ├── wider_pr_info_vj_easy.mat │ │ │ │ │ ├── wider_pr_info_vj_hard.mat │ │ │ │ │ └── wider_pr_info_vj_medium.mat │ │ │ └── setting_int │ │ │ │ ├── DSFD │ │ │ │ ├── wider_pr_info_DSFD_easy.mat │ │ │ │ ├── wider_pr_info_DSFD_hard.mat │ │ │ │ └── wider_pr_info_DSFD_medium.mat │ │ │ │ ├── FAN │ │ │ │ ├── wider_pr_info_FAN_easy.mat │ │ │ │ ├── wider_pr_info_FAN_hard.mat │ │ │ │ └── wider_pr_info_FAN_medium.mat │ │ │ │ ├── FANet │ │ │ │ ├── wider_pr_info_FANet_easy.mat │ │ │ │ ├── wider_pr_info_FANet_hard.mat │ │ │ │ └── wider_pr_info_FANet_medium.mat │ │ │ │ ├── FDNet │ │ │ │ ├── wider_pr_info_FDNet_easy.mat │ │ │ │ ├── wider_pr_info_FDNet_hard.mat │ │ │ │ └── wider_pr_info_FDNet_medium.mat │ │ │ │ ├── Face R-CNN │ │ │ │ ├── wider_pr_info_Face R-CNN_easy.mat │ │ │ │ ├── wider_pr_info_Face R-CNN_hard.mat │ │ │ │ └── wider_pr_info_Face R-CNN_medium.mat │ │ │ │ ├── Face R-FCN │ │ │ │ ├── wider_pr_info_Face R-FCN_easy.mat │ │ │ │ ├── wider_pr_info_Face R-FCN_hard.mat │ │ │ │ └── wider_pr_info_Face R-FCN_medium.mat │ │ │ │ ├── HR │ │ │ │ ├── wider_pr_info_HR_easy.mat │ │ │ │ ├── wider_pr_info_HR_hard.mat │ │ │ │ └── wider_pr_info_HR_medium.mat │ │ │ │ ├── LDCF+ │ │ │ │ ├── wider_pr_info_LDCF+_easy.mat │ │ │ │ ├── wider_pr_info_LDCF+_hard.mat │ │ │ │ └── wider_pr_info_LDCF+_medium.mat │ │ │ │ ├── MSCNN │ │ │ │ ├── wider_pr_info_MSCNN_easy.mat │ │ │ │ ├── wider_pr_info_MSCNN_hard.mat │ │ │ │ └── wider_pr_info_MSCNN_medium.mat │ │ │ │ ├── PyramidBox │ │ │ │ ├── wider_pr_info_PyramidBox_easy.mat │ │ │ │ ├── wider_pr_info_PyramidBox_hard.mat │ │ │ │ └── wider_pr_info_PyramidBox_medium.mat │ │ │ │ ├── SFD │ │ │ │ ├── wider_pr_info_SFD_easy.mat │ │ │ │ ├── wider_pr_info_SFD_hard.mat │ │ │ │ └── wider_pr_info_SFD_medium.mat │ │ │ │ ├── SRN │ │ │ │ ├── wider_pr_info_SRN_easy.mat │ │ │ │ ├── wider_pr_info_SRN_hard.mat │ │ │ │ └── wider_pr_info_SRN_medium.mat │ │ │ │ ├── SSH │ │ │ │ ├── wider_pr_info_SSH_easy.mat │ │ │ │ ├── wider_pr_info_SSH_hard.mat │ │ │ │ └── wider_pr_info_SSH_medium.mat │ │ │ │ ├── ScaleFace │ │ │ │ ├── wider_pr_info_ScaleFace_easy.mat │ │ │ │ ├── wider_pr_info_ScaleFace_hard.mat │ │ │ │ └── wider_pr_info_ScaleFace_medium.mat │ │ │ │ ├── ZCC │ │ │ │ ├── wider_pr_info_ZCC_easy.mat │ │ │ │ ├── wider_pr_info_ZCC_hard.mat │ │ │ │ └── wider_pr_info_ZCC_medium.mat │ │ │ │ ├── acf │ │ │ │ ├── wider_pr_info_acf_easy.mat │ │ │ │ ├── wider_pr_info_acf_hard.mat │ │ │ │ └── wider_pr_info_acf_medium.mat │ │ │ │ ├── cms-rcnn │ │ │ │ ├── wider_pr_info_cms-rcnn_easy.mat │ │ │ │ ├── wider_pr_info_cms-rcnn_hard.mat │ │ │ │ └── wider_pr_info_cms-rcnn_medium.mat │ │ │ │ ├── faceness │ │ │ │ ├── wider_pr_info_faceness_easy.mat │ │ │ │ ├── wider_pr_info_faceness_hard.mat │ │ │ │ └── wider_pr_info_faceness_medium.mat │ │ │ │ ├── multiscale_cascade │ │ │ │ ├── wider_pr_info_multiscale_cascade_easy.mat │ │ │ │ ├── wider_pr_info_multiscale_cascade_hard.mat │ │ │ │ └── wider_pr_info_multiscale_cascade_medium.mat │ │ │ │ ├── multitask-cascade-cnn │ │ │ │ ├── wider_pr_info_multitask-cascade-cnn_easy.mat │ │ │ │ ├── wider_pr_info_multitask-cascade-cnn_hard.mat │ │ │ │ └── wider_pr_info_multitask-cascade-cnn_medium.mat │ │ │ │ └── two_stage_cnn │ │ │ │ ├── wider_pr_info_two_stage_cnn_easy.mat │ │ │ │ ├── wider_pr_info_two_stage_cnn_hard.mat │ │ │ │ └── wider_pr_info_two_stage_cnn_medium.mat │ │ └── Val │ │ │ └── setting_int │ │ │ ├── DSFD │ │ │ ├── wider_pr_info_DSFD_easy_val.mat │ │ │ ├── wider_pr_info_DSFD_hard_val.mat │ │ │ └── wider_pr_info_DSFD_medium_val.mat │ │ │ ├── FAN │ │ │ ├── wider_pr_info_fan_easy_val.mat │ │ │ ├── wider_pr_info_fan_hard_val.mat │ │ │ └── wider_pr_info_fan_medium_val.mat │ │ │ ├── FANet │ │ │ ├── wider_pr_info_FANet_easy_val.mat │ │ │ ├── wider_pr_info_FANet_hard_val.mat │ │ │ └── wider_pr_info_FANet_medium_val.mat │ │ │ ├── FDNet │ │ │ ├── wider_pr_info_FDNet_easy_val.mat │ │ │ ├── wider_pr_info_FDNet_hard_val.mat │ │ │ └── wider_pr_info_FDNet_medium_val.mat │ │ │ ├── Face R-CNN │ │ │ ├── wider_pr_info_Face R-CNN_easy_val.mat │ │ │ ├── wider_pr_info_Face R-CNN_hard_val.mat │ │ │ └── wider_pr_info_Face R-CNN_medium_val.mat │ │ │ ├── Face R-FCN │ │ │ ├── wider_pr_info_Face R-FCN_easy_val.mat │ │ │ ├── wider_pr_info_Face R-FCN_hard_val.mat │ │ │ └── wider_pr_info_Face R-FCN_medium_val.mat │ │ │ ├── HR │ │ │ ├── wider_pr_info_HR_easy_val.mat │ │ │ ├── wider_pr_info_HR_hard_val.mat │ │ │ └── wider_pr_info_HR_medium_val.mat │ │ │ ├── LDCF+ │ │ │ ├── wider_pr_info_LDCF+_easy_val.mat │ │ │ ├── wider_pr_info_LDCF+_hard_val.mat │ │ │ └── wider_pr_info_LDCF+_medium_val.mat │ │ │ ├── MSCNN │ │ │ ├── wider_pr_info_MSCNN_easy_val.mat │ │ │ ├── wider_pr_info_MSCNN_hard_val.mat │ │ │ └── wider_pr_info_MSCNN_medium_val.mat │ │ │ ├── PyramidBox │ │ │ ├── wider_pr_info_PyramidBox_easy_val.mat │ │ │ ├── wider_pr_info_PyramidBox_hard_val.mat │ │ │ └── wider_pr_info_PyramidBox_medium_val.mat │ │ │ ├── SFD │ │ │ ├── wider_pr_info_SFD_easy_val.mat │ │ │ ├── wider_pr_info_SFD_hard_val.mat │ │ │ └── wider_pr_info_SFD_medium_val.mat │ │ │ ├── SRN │ │ │ ├── wider_pr_info_SRN_easy_val.mat │ │ │ ├── wider_pr_info_SRN_hard_val.mat │ │ │ └── wider_pr_info_SRN_medium_val.mat │ │ │ ├── SSH │ │ │ ├── wider_pr_info_SSH_easy_val.mat │ │ │ ├── wider_pr_info_SSH_hard_val.mat │ │ │ └── wider_pr_info_SSH_medium_val.mat │ │ │ ├── ScaleFace │ │ │ ├── wider_pr_info_ScaleFace_easy_val.mat │ │ │ ├── wider_pr_info_ScaleFace_hard_val.mat │ │ │ └── wider_pr_info_ScaleFace_medium_val.mat │ │ │ ├── ZCC │ │ │ ├── wider_pr_info_ZCC_easy_val.mat │ │ │ ├── wider_pr_info_ZCC_hard_val.mat │ │ │ └── wider_pr_info_ZCC_medium_val.mat │ │ │ ├── acf │ │ │ ├── wider_pr_info_acf_easy_val.mat │ │ │ ├── wider_pr_info_acf_hard_val.mat │ │ │ └── wider_pr_info_acf_medium_val.mat │ │ │ ├── cms-rcnn │ │ │ ├── wider_pr_info_cms-rcnn_easy_val.mat │ │ │ ├── wider_pr_info_cms-rcnn_hard_val.mat │ │ │ └── wider_pr_info_cms-rcnn_medium_val.mat │ │ │ ├── faceness │ │ │ ├── wider_pr_info_faceness_easy_val.mat │ │ │ ├── wider_pr_info_faceness_hard_val.mat │ │ │ └── wider_pr_info_faceness_medium_val.mat │ │ │ ├── multiscale_cascade │ │ │ ├── wider_pr_info_multiscale_cascade_easy_val.mat │ │ │ ├── wider_pr_info_multiscale_cascade_hard_val.mat │ │ │ └── wider_pr_info_multiscale_cascade_medium_val.mat │ │ │ ├── multitask-cascade-cnn │ │ │ ├── wider_pr_info_multitask-cascade-cnn_easy_val.mat │ │ │ ├── wider_pr_info_multitask-cascade-cnn_hard_val.mat │ │ │ └── wider_pr_info_multitask-cascade-cnn_medium_val.mat │ │ │ ├── s3fd.pytorch │ │ │ ├── wider_pr_info_s3fd.pytorch_easy_val.mat │ │ │ ├── wider_pr_info_s3fd.pytorch_hard_val.mat │ │ │ └── wider_pr_info_s3fd.pytorch_medium_val.mat │ │ │ └── two_stage_cnn │ │ │ ├── wider_pr_info_two_stage_cnn_easy_val.mat │ │ │ ├── wider_pr_info_two_stage_cnn_hard_val.mat │ │ │ └── wider_pr_info_two_stage_cnn_medium_val.mat │ └── figure │ │ ├── Test │ │ ├── wider_pr_cruve_ext_easy.pdf │ │ ├── wider_pr_cruve_ext_hard.pdf │ │ ├── wider_pr_cruve_ext_medium.pdf │ │ ├── wider_pr_cruve_int_easy.pdf │ │ ├── wider_pr_cruve_int_hard.pdf │ │ └── wider_pr_cruve_int_medium.pdf │ │ └── Val │ │ ├── wider_pr_cruve_int_easy_val.pdf │ │ ├── wider_pr_cruve_int_hard_val.pdf │ │ └── wider_pr_cruve_int_medium_val.pdf ├── wider_face_test.mat └── wider_face_val.mat ├── img └── blackpink.jpg ├── layers ├── bbox_utils.py ├── functions │ ├── detection.py │ └── prior_box.py └── modules │ ├── l2norm.py │ └── multibox_loss.py ├── logger.py ├── logs └── tensorboard │ └── empty ├── mobileFacenet_32_PReLU.py ├── mobileFacenet_48_PReLU.py ├── mobileFacenet_64_PReLU.py ├── prepare_hand_dataset.py ├── prepare_wider_data.py ├── setup.py ├── tmp └── blackpink.jpg ├── tools ├── afw_img_list.txt ├── afw_test.py ├── anchor_matching_test.py ├── detect.py ├── eval_hand.py ├── eval_head.py ├── fddb_test.py ├── pascal_img_list.txt ├── pascal_test.py └── wider_test.py ├── train.py ├── utils ├── __init__.py └── augmentations.py ├── weights ├── EXTD_32.pth ├── EXTD_48.pth └── EXTD_64.pth └── wider_test.py /EXTD_48.py: -------------------------------------------------------------------------------- 1 | ''' 2 | EXTD Copyright (c) 2019-present NAVER Corp. MIT License 3 | ''' 4 | # -*- coding:utf-8 -*- 5 | 6 | from __future__ import division 7 | from __future__ import absolute_import 8 | from __future__ import print_function 9 | 10 | import os 11 | import torch 12 | import torch.nn as nn 13 | import torch.nn.init as init 14 | import torch.nn.functional as F 15 | from layers.modules.l2norm import L2Norm 16 | from layers.functions.prior_box import PriorBox 17 | from layers.functions.detection import Detect 18 | from torch.autograd import Variable 19 | 20 | from layers import * 21 | from data.config import cfg 22 | import numpy as np 23 | 24 | import mobileFacenet_48_PReLU 25 | 26 | 27 | def upsample(in_channels, out_channels): # should use F.inpterpolate 28 | return nn.Sequential( 29 | nn.Conv2d(in_channels=in_channels, out_channels=in_channels, kernel_size=(3, 3), 30 | stride=1, padding=1, groups=in_channels, bias=False), 31 | nn.Conv2d(in_channels=in_channels, out_channels=out_channels, kernel_size=1, stride=1, padding=0, 32 | bias=False), 33 | nn.BatchNorm2d(out_channels), 34 | nn.ReLU() 35 | ) 36 | 37 | 38 | class EXTD(nn.Module): 39 | """Single Shot Multibox Architecture 40 | The network is composed of a base VGG network followed by the 41 | added multibox conv layers. Each multibox layer branches into 42 | 1) conv2d for class conf scores 43 | 2) conv2d for localization predictions 44 | 3) associated priorbox layer to produce default bounding 45 | boxes specific to the layer's feature map size. 46 | See: https://arxiv.org/pdf/1512.02325.pdf for more details. 47 | 48 | 49 | Args: 50 | phase: (string) Can be "test" or "train" 51 | size: input image size 52 | base: VGG16 layers for input, size of either 300 or 500 53 | extras: extra layers that feed to multibox loc and conf layers 54 | head: "multibox head" consists of loc and conf conv layers 55 | """ 56 | 57 | def __init__(self, phase, base, head, num_classes): 58 | super(EXTD, self).__init__() 59 | self.phase = phase 60 | self.num_classes = num_classes 61 | 62 | # SSD network 63 | self.base = nn.ModuleList(base) 64 | 65 | self.upfeat = [] 66 | 67 | for it in range(5): 68 | self.upfeat.append(upsample(in_channels=48, out_channels=48)) 69 | 70 | self.upfeat = nn.ModuleList(self.upfeat) 71 | 72 | self.loc = nn.ModuleList(head[0]) 73 | self.conf = nn.ModuleList(head[1]) 74 | 75 | if self.phase == 'test': 76 | self.softmax = nn.Softmax(dim=-1) 77 | self.detect = Detect(cfg) 78 | 79 | def forward(self, x): 80 | """Applies network layers and ops on input image(s) x. 81 | 82 | Args: 83 | x: input image or batch of images. Shape: [batch,3,300,300]. 84 | 85 | Return: 86 | Depending on phase: 87 | test: 88 | Variable(tensor) of output class label predictions, 89 | confidence score, and corresponding location predictions for 90 | each object detected. Shape: [batch,topk,7] 91 | 92 | train: 93 | list of concat outputs from: 94 | 1: confidence layers, Shape: [batch*num_priors,num_classes] 95 | 2: localization layers, Shape: [batch,num_priors*4] 96 | 3: priorbox layers, Shape: [2,num_priors*4] 97 | """ 98 | size = x.size()[2:] 99 | sources = list() 100 | loc = list() 101 | conf = list() 102 | 103 | # apply vgg up to conv4_3 relu 104 | for k in range(6): 105 | x = self.base[k](x) 106 | 107 | s1 = x 108 | 109 | # apply vgg up to fc7 110 | for k in range(2, 6): 111 | x = self.base[k](x) 112 | 113 | s2 = x 114 | 115 | 116 | for k in range(2, 6): 117 | x = self.base[k](x) 118 | 119 | s3 = x 120 | 121 | 122 | for k in range(2, 6): 123 | x = self.base[k](x) 124 | 125 | s4 = x 126 | 127 | 128 | for k in range(2, 6): 129 | x = self.base[k](x) 130 | 131 | s5 = x 132 | 133 | 134 | for k in range(2, 6): 135 | x = self.base[k](x) 136 | 137 | s6 = x 138 | 139 | sources.append(s6) 140 | 141 | u1 = self.upfeat[0](F.interpolate(s6, size=(s5.size()[2], s5.size()[3]), mode='bilinear')) + s5 # 10x10 142 | sources.append(u1) 143 | 144 | u2 = self.upfeat[1](F.interpolate(u1, size=(s4.size()[2], s4.size()[3]), mode='bilinear')) + s4 # 20x20 145 | sources.append(u2) 146 | 147 | u3 = self.upfeat[2](F.interpolate(u2, size=(s3.size()[2], s3.size()[3]), mode='bilinear')) + s3 # 40x40 148 | sources.append(u3) 149 | 150 | u4 = self.upfeat[3](F.interpolate(u3, size=(s2.size()[2], s2.size()[3]), mode='bilinear')) + s2 # 80x80 151 | sources.append(u4) 152 | 153 | u5 = self.upfeat[4](F.interpolate(u4, size=(s1.size()[2], s1.size()[3]), mode='bilinear')) + s1 # 160x160 154 | sources.append(u5) 155 | 156 | sources = sources[::-1] # reverse order 157 | 158 | 159 | # apply multibox head to source layers 160 | 161 | loc_x = self.loc[0](sources[0]) 162 | conf_x = self.conf[0](sources[0]) 163 | 164 | max_conf, _ = torch.max(conf_x[:, 0:3, :, :], dim=1, keepdim=True) 165 | conf_x = torch.cat((max_conf, conf_x[:, 3:, :, :]), dim=1) 166 | 167 | loc.append(loc_x.permute(0, 2, 3, 1).contiguous()) 168 | conf.append(conf_x.permute(0, 2, 3, 1).contiguous()) 169 | 170 | for i in range(1, len(sources)): 171 | x = sources[i] 172 | conf.append(self.conf[i](x).permute(0, 2, 3, 1).contiguous()) 173 | loc.append(self.loc[i](x).permute(0, 2, 3, 1).contiguous()) 174 | 175 | 176 | features_maps = [] 177 | for i in range(len(loc)): 178 | feat = [] 179 | feat += [loc[i].size(1), loc[i].size(2)] 180 | features_maps += [feat] 181 | 182 | self.priorbox = PriorBox(size, features_maps, cfg) 183 | self.priors = Variable(self.priorbox.forward(), volatile=True) 184 | 185 | loc = torch.cat([o.view(o.size(0), -1) for o in loc], 1) 186 | conf = torch.cat([o.view(o.size(0), -1) for o in conf], 1) 187 | 188 | if self.phase == 'test': 189 | output = self.detect( 190 | loc.view(loc.size(0), -1, 4), # loc preds 191 | self.softmax(conf.view(conf.size(0), -1, 192 | self.num_classes)), # conf preds 193 | self.priors.type(type(x.data)) # default boxes 194 | ) 195 | 196 | else: 197 | output = ( 198 | loc.view(loc.size(0), -1, 4), 199 | conf.view(conf.size(0), -1, self.num_classes), 200 | self.priors 201 | ) 202 | return output 203 | 204 | def load_weights(self, base_file): 205 | other, ext = os.path.splitext(base_file) 206 | if ext == '.pkl' or '.pth': 207 | print('Loading weights into state dict...') 208 | mdata = torch.load(base_file, 209 | map_location=lambda storage, loc: storage) 210 | weights = mdata['weight'] 211 | epoch = mdata['epoch'] 212 | self.load_state_dict(weights) 213 | print('Finished!') 214 | else: 215 | print('Sorry only .pth and .pkl files supported.') 216 | return epoch 217 | 218 | def xavier(self, param): 219 | init.xavier_uniform(param) 220 | 221 | def weights_init(self, m): 222 | if isinstance(m, nn.Conv2d): 223 | self.xavier(m.weight.data) 224 | if torch.is_tensor(m.bias): 225 | m.bias.data.zero_() 226 | 227 | 228 | 229 | 230 | def mobileFacenet(): 231 | net = mobileFacenet_48_PReLU.Net() 232 | #print(net) 233 | return nn.ModuleList(net.features) 234 | 235 | 236 | def add_extras(cfg, i, batch_norm=False): 237 | # Extra layers added to VGG for feature scaling 238 | layers = [] 239 | in_channels = i 240 | flag = False 241 | for k, v in enumerate(cfg): 242 | if in_channels != 'S': 243 | if v == 'S': 244 | layers += [nn.Conv2d(in_channels, cfg[k + 1], 245 | kernel_size=(1, 3)[flag], stride=2, padding=1, bias=False), 246 | nn.BatchNorm2d(cfg[k + 1]), nn.ReLU(inplace=True)] 247 | else: 248 | layers += [nn.Conv2d(in_channels, v, kernel_size=(1, 3)[flag], bias=False), 249 | nn.BatchNorm2d(v), nn.ReLU(inplace=True)] 250 | flag = not flag 251 | in_channels = v 252 | return layers 253 | 254 | 255 | def add_extras_mobileFace(in_channel=32): 256 | layers = [] 257 | channels = [in_channel] 258 | for v in channels: 259 | layers += [ 260 | nn.Conv2d(in_channels=in_channel, out_channels=v, kernel_size=(3, 3), stride=2, padding=1, bias=False), 261 | nn.BatchNorm2d(v), 262 | nn.ReLU(inplace=True)] 263 | 264 | return layers 265 | 266 | 267 | def add_extras_dwc(cfg, i, batch_norm=False): 268 | # Extra layers added to VGG for feature scaling 269 | layers = [] 270 | in_channels = i 271 | flag = False 272 | for k, v in enumerate(cfg): 273 | if in_channels != 'S': 274 | if v == 'S': 275 | layers += [nn.Conv2d(in_channels, in_channels, 276 | kernel_size=3, stride=2, padding=1, bias=False, groups=in_channels), 277 | nn.BatchNorm2d(in_channels), nn.ReLU(inplace=True)] 278 | layers += [nn.Conv2d(in_channels, cfg[k + 1], 279 | kernel_size=1, stride=1, bias=False), 280 | nn.BatchNorm2d(cfg[k + 1]), nn.ReLU(inplace=True)] 281 | else: 282 | layers += [nn.Conv2d(in_channels, v, kernel_size=1, bias=False), 283 | nn.BatchNorm2d(v), nn.ReLU(inplace=True)] 284 | flag = not flag 285 | in_channels = v 286 | return layers 287 | 288 | 289 | def multibox(base, extra_layers, num_classes): 290 | loc_layers = [] 291 | conf_layers = [] 292 | net_source = [4, 4, 4, 4] 293 | feature_dim = [] 294 | 295 | feature_dim += [base[4].conv[-2].out_channels] 296 | for idx in net_source: 297 | feature_dim += [base[idx].conv[-2].out_channels] 298 | 299 | #print(feature_dim) 300 | 301 | loc_layers += [nn.Conv2d(feature_dim[0], 4, kernel_size=3, padding=1)] 302 | conf_layers += [nn.Conv2d(feature_dim[0], 3 + (num_classes - 1), kernel_size=3, padding=1)] 303 | 304 | for k, v in enumerate(net_source, 1): 305 | loc_layers += [nn.Conv2d(feature_dim[k], 4, kernel_size=3, padding=1)] 306 | conf_layers += [nn.Conv2d(feature_dim[k], num_classes, kernel_size=3, padding=1)] 307 | 308 | # for k, v in enumerate(extra_layers[3::6], 2): 309 | 310 | for v in [0]: 311 | print(extra_layers[v].out_channels) 312 | loc_layers += [nn.Conv2d(extra_layers[v].out_channels, 313 | 4, kernel_size=3, padding=1)] 314 | conf_layers += [nn.Conv2d(extra_layers[v].out_channels, 315 | num_classes, kernel_size=3, padding=1)] 316 | 317 | return base[:6], extra_layers, (loc_layers, conf_layers) 318 | 319 | 320 | def build_extd(phase, num_classes=2): 321 | base_, extras_, head_ = multibox( 322 | mobileFacenet(), add_extras_mobileFace(in_channel=48), num_classes) 323 | 324 | return EXTD(phase, base_, head_, num_classes) 325 | 326 | 327 | if __name__ == '__main__': 328 | net = build_extd('train', num_classes=2) 329 | inputs = Variable(torch.randn(4, 3, 640, 640)) 330 | output = net(inputs) 331 | # print(output) 332 | 333 | -------------------------------------------------------------------------------- /EXTD_64.py: -------------------------------------------------------------------------------- 1 | ''' 2 | EXTD Copyright (c) 2019-present NAVER Corp. MIT License 3 | ''' 4 | # -*- coding:utf-8 -*- 5 | 6 | from __future__ import division 7 | from __future__ import absolute_import 8 | from __future__ import print_function 9 | 10 | import os 11 | import torch 12 | import torch.nn as nn 13 | import torch.nn.init as init 14 | import torch.nn.functional as F 15 | from layers.modules.l2norm import L2Norm 16 | from layers.functions.prior_box import PriorBox 17 | from layers.functions.detection import Detect 18 | from torch.autograd import Variable 19 | 20 | from layers import * 21 | from data.config import cfg 22 | import numpy as np 23 | 24 | import mobileFacenet_64_PReLU as mobileFacenet_11 25 | 26 | 27 | def upsample(in_channels, out_channels): # should use F.inpterpolate 28 | return nn.Sequential( 29 | nn.Conv2d(in_channels=in_channels, out_channels=in_channels, kernel_size=(3, 3), 30 | stride=1, padding=1, groups=in_channels, bias=False), 31 | nn.Conv2d(in_channels=in_channels, out_channels=out_channels, kernel_size=1, stride=1, padding=0, 32 | bias=False), 33 | nn.BatchNorm2d(out_channels), 34 | nn.ReLU() 35 | ) 36 | 37 | 38 | class EXTD(nn.Module): 39 | """Single Shot Multibox Architecture 40 | The network is composed of a base VGG network followed by the 41 | added multibox conv layers. Each multibox layer branches into 42 | 1) conv2d for class conf scores 43 | 2) conv2d for localization predictions 44 | 3) associated priorbox layer to produce default bounding 45 | boxes specific to the layer's feature map size. 46 | See: https://arxiv.org/pdf/1512.02325.pdf for more details. 47 | 48 | 49 | Args: 50 | phase: (string) Can be "test" or "train" 51 | size: input image size 52 | base: VGG16 layers for input, size of either 300 or 500 53 | extras: extra layers that feed to multibox loc and conf layers 54 | head: "multibox head" consists of loc and conf conv layers 55 | """ 56 | 57 | def __init__(self, phase, base, head, num_classes): 58 | super(EXTD, self).__init__() 59 | self.phase = phase 60 | self.num_classes = num_classes 61 | 62 | # SSD network 63 | self.base = nn.ModuleList(base) 64 | 65 | self.upfeat = [] 66 | 67 | for it in range(5): 68 | self.upfeat.append(upsample(in_channels=64, out_channels=64)) 69 | 70 | self.upfeat = nn.ModuleList(self.upfeat) 71 | 72 | self.loc = nn.ModuleList(head[0]) 73 | self.conf = nn.ModuleList(head[1]) 74 | 75 | if self.phase == 'test': 76 | self.softmax = nn.Softmax(dim=-1) 77 | self.detect = Detect(cfg) 78 | 79 | def forward(self, x): 80 | """Applies network layers and ops on input image(s) x. 81 | 82 | Args: 83 | x: input image or batch of images. Shape: [batch,3,300,300]. 84 | 85 | Return: 86 | Depending on phase: 87 | test: 88 | Variable(tensor) of output class label predictions, 89 | confidence score, and corresponding location predictions for 90 | each object detected. Shape: [batch,topk,7] 91 | 92 | train: 93 | list of concat outputs from: 94 | 1: confidence layers, Shape: [batch*num_priors,num_classes] 95 | 2: localization layers, Shape: [batch,num_priors*4] 96 | 3: priorbox layers, Shape: [2,num_priors*4] 97 | """ 98 | size = x.size()[2:] 99 | sources = list() 100 | loc = list() 101 | conf = list() 102 | 103 | # apply vgg up to conv4_3 relu 104 | for k in range(6): 105 | x = self.base[k](x) 106 | 107 | s1 = x 108 | 109 | # apply vgg up to fc7 110 | for k in range(2, 6): 111 | x = self.base[k](x) 112 | 113 | s2 = x 114 | 115 | for k in range(2, 6): 116 | x = self.base[k](x) 117 | 118 | s3 = x 119 | 120 | for k in range(2, 6): 121 | x = self.base[k](x) 122 | 123 | s4 = x 124 | 125 | 126 | for k in range(2, 6): 127 | x = self.base[k](x) 128 | 129 | s5 = x 130 | 131 | 132 | for k in range(2, 6): 133 | x = self.base[k](x) 134 | 135 | s6 = x 136 | 137 | sources.append(s6) 138 | 139 | u1 = self.upfeat[0](F.interpolate(s6, size=(s5.size()[2], s5.size()[3]), mode='bilinear')) + s5 # 10x10 140 | sources.append(u1) 141 | 142 | u2 = self.upfeat[1](F.interpolate(u1, size=(s4.size()[2], s4.size()[3]), mode='bilinear')) + s4 # 20x20 143 | sources.append(u2) 144 | 145 | u3 = self.upfeat[2](F.interpolate(u2, size=(s3.size()[2], s3.size()[3]), mode='bilinear')) + s3 # 40x40 146 | sources.append(u3) 147 | 148 | u4 = self.upfeat[3](F.interpolate(u3, size=(s2.size()[2], s2.size()[3]), mode='bilinear')) + s2 # 80x80 149 | sources.append(u4) 150 | 151 | u5 = self.upfeat[4](F.interpolate(u4, size=(s1.size()[2], s1.size()[3]), mode='bilinear')) + s1 # 160x160 152 | sources.append(u5) 153 | 154 | sources = sources[::-1] # reverse order 155 | 156 | # apply extra layers and cache source layer outputs 157 | #for k, v in enumerate(self.extras): 158 | # x = v(x) 159 | # if k in self.extras_idx: 160 | # sources.append(x) 161 | 162 | # apply multibox head to source layers 163 | 164 | loc_x = self.loc[0](sources[0]) 165 | conf_x = self.conf[0](sources[0]) 166 | 167 | max_conf, _ = torch.max(conf_x[:, 0:3, :, :], dim=1, keepdim=True) 168 | conf_x = torch.cat((max_conf, conf_x[:, 3:, :, :]), dim=1) 169 | 170 | loc.append(loc_x.permute(0, 2, 3, 1).contiguous()) 171 | conf.append(conf_x.permute(0, 2, 3, 1).contiguous()) 172 | 173 | for i in range(1, len(sources)): 174 | x = sources[i] 175 | conf.append(self.conf[i](x).permute(0, 2, 3, 1).contiguous()) 176 | loc.append(self.loc[i](x).permute(0, 2, 3, 1).contiguous()) 177 | 178 | 179 | features_maps = [] 180 | for i in range(len(loc)): 181 | feat = [] 182 | feat += [loc[i].size(1), loc[i].size(2)] 183 | features_maps += [feat] 184 | 185 | self.priorbox = PriorBox(size, features_maps, cfg) 186 | self.priors = Variable(self.priorbox.forward(), volatile=True) 187 | 188 | loc = torch.cat([o.view(o.size(0), -1) for o in loc], 1) 189 | conf = torch.cat([o.view(o.size(0), -1) for o in conf], 1) 190 | 191 | if self.phase == 'test': 192 | output = self.detect( 193 | loc.view(loc.size(0), -1, 4), # loc preds 194 | self.softmax(conf.view(conf.size(0), -1, 195 | self.num_classes)), # conf preds 196 | self.priors.type(type(x.data)) # default boxes 197 | ) 198 | 199 | else: 200 | output = ( 201 | loc.view(loc.size(0), -1, 4), 202 | conf.view(conf.size(0), -1, self.num_classes), 203 | self.priors 204 | ) 205 | return output 206 | 207 | def load_weights(self, base_file): 208 | other, ext = os.path.splitext(base_file) 209 | if ext == '.pkl' or '.pth': 210 | print('Loading weights into state dict...') 211 | mdata = torch.load(base_file, 212 | map_location=lambda storage, loc: storage) 213 | weights = mdata['weight'] 214 | epoch = mdata['epoch'] 215 | self.load_state_dict(weights) 216 | print('Finished!') 217 | else: 218 | print('Sorry only .pth and .pkl files supported.') 219 | return epoch 220 | 221 | def xavier(self, param): 222 | init.xavier_uniform(param) 223 | 224 | def weights_init(self, m): 225 | if isinstance(m, nn.Conv2d): 226 | self.xavier(m.weight.data) 227 | if torch.is_tensor(m.bias): 228 | m.bias.data.zero_() 229 | 230 | 231 | 232 | def mobileFacenet(): 233 | net = mobileFacenet_11.Net() 234 | #print(net) 235 | return nn.ModuleList(net.features) 236 | 237 | 238 | def add_extras(cfg, i, batch_norm=False): 239 | # Extra layers added to VGG for feature scaling 240 | layers = [] 241 | in_channels = i 242 | flag = False 243 | for k, v in enumerate(cfg): 244 | if in_channels != 'S': 245 | if v == 'S': 246 | layers += [nn.Conv2d(in_channels, cfg[k + 1], 247 | kernel_size=(1, 3)[flag], stride=2, padding=1, bias=False), 248 | nn.BatchNorm2d(cfg[k + 1]), nn.ReLU(inplace=True)] 249 | else: 250 | layers += [nn.Conv2d(in_channels, v, kernel_size=(1, 3)[flag], bias=False), 251 | nn.BatchNorm2d(v), nn.ReLU(inplace=True)] 252 | flag = not flag 253 | in_channels = v 254 | return layers 255 | 256 | 257 | def add_extras_mobileFace(in_channel=32): 258 | layers = [] 259 | channels = [in_channel] 260 | for v in channels: 261 | layers += [ 262 | nn.Conv2d(in_channels=in_channel, out_channels=v, kernel_size=(3, 3), stride=2, padding=1, bias=False), 263 | nn.BatchNorm2d(v), 264 | nn.ReLU(inplace=True)] 265 | 266 | return layers 267 | 268 | 269 | def add_extras_dwc(cfg, i, batch_norm=False): 270 | # Extra layers added to VGG for feature scaling 271 | layers = [] 272 | in_channels = i 273 | flag = False 274 | for k, v in enumerate(cfg): 275 | if in_channels != 'S': 276 | if v == 'S': 277 | layers += [nn.Conv2d(in_channels, in_channels, 278 | kernel_size=3, stride=2, padding=1, bias=False, groups=in_channels), 279 | nn.BatchNorm2d(in_channels), nn.ReLU(inplace=True)] 280 | layers += [nn.Conv2d(in_channels, cfg[k + 1], 281 | kernel_size=1, stride=1, bias=False), 282 | nn.BatchNorm2d(cfg[k + 1]), nn.ReLU(inplace=True)] 283 | else: 284 | layers += [nn.Conv2d(in_channels, v, kernel_size=1, bias=False), 285 | nn.BatchNorm2d(v), nn.ReLU(inplace=True)] 286 | flag = not flag 287 | in_channels = v 288 | return layers 289 | 290 | 291 | def multibox(base, extra_layers, num_classes): 292 | loc_layers = [] 293 | conf_layers = [] 294 | net_source = [4, 4, 4, 4] 295 | feature_dim = [] 296 | 297 | feature_dim += [base[4].conv[-2].out_channels] 298 | for idx in net_source: 299 | feature_dim += [base[idx].conv[-2].out_channels] 300 | 301 | #print(feature_dim) 302 | 303 | loc_layers += [nn.Conv2d(feature_dim[0], 4, kernel_size=3, padding=1)] 304 | conf_layers += [nn.Conv2d(feature_dim[0], 3 + (num_classes - 1), kernel_size=3, padding=1)] 305 | 306 | for k, v in enumerate(net_source, 1): 307 | loc_layers += [nn.Conv2d(feature_dim[k], 4, kernel_size=3, padding=1)] 308 | conf_layers += [nn.Conv2d(feature_dim[k], num_classes, kernel_size=3, padding=1)] 309 | 310 | # for k, v in enumerate(extra_layers[3::6], 2): 311 | 312 | for v in [0]: 313 | print(extra_layers[v].out_channels) 314 | loc_layers += [nn.Conv2d(extra_layers[v].out_channels, 315 | 4, kernel_size=3, padding=1)] 316 | conf_layers += [nn.Conv2d(extra_layers[v].out_channels, 317 | num_classes, kernel_size=3, padding=1)] 318 | 319 | return base[:6], extra_layers, (loc_layers, conf_layers) 320 | 321 | 322 | def build_extd(phase, num_classes=2): 323 | base_, extras_, head_ = multibox( 324 | mobileFacenet(), add_extras_mobileFace(in_channel=64), num_classes) 325 | 326 | return EXTD(phase, base_, head_, num_classes) 327 | 328 | 329 | if __name__ == '__main__': 330 | net = build_extd('train', num_classes=2) 331 | inputs = Variable(torch.randn(4, 3, 640, 640)) 332 | output = net(inputs) 333 | # print(output) 334 | 335 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019-present NAVER Corp. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## EXTD: Extremely Tiny Face Detector via Iterative Filter Reuse ## 2 | A PyTorch Implementation of Extremely Tiny Face Detector via Iterative Filter Reuse 3 | 4 | YoungJoon Yoo, Dongyoon Han, Sangdoo Yun 5 | 6 | https://arxiv.org/abs/1906.06579 7 | 8 | ![extd_teaser](https://user-images.githubusercontent.com/12525981/62098369-f7aaa280-b2c4-11e9-80dc-7c21fbeda652.png) 9 | ![table](https://user-images.githubusercontent.com/12525981/62098372-faa59300-b2c4-11e9-8ed7-6ef302eace46.png) 10 | 11 | 12 | ### Requirement 13 | * pytorch 1.0 (checked at 1.0) 14 | * opencv 15 | * numpy 16 | * easydict 17 | * Python3 18 | 19 | ### Prepare data 20 | WIDER face dataset is used. see the S3FD.pytorch git for more detail. 21 | 22 | 23 | ### Train 24 | You can use 25 | ``` 26 | python train.py 27 | ``` 28 | 29 | Refer the train.py files to check the arguement. 30 | Our setting was 31 | 32 | ``` 33 | "--batch_size 16 --lr 0.001" 34 | ``` 35 | 36 | ### Evaluation on WIDER Dataset 37 | You should complie the bounding box function. Type 38 | ``` 39 | python3 bbox_setup.py build_ext --inplace 40 | ``` 41 | 42 | Then run 43 | ``` 44 | python3 wider_test.py 45 | ``` 46 | 47 | ### Demo 48 | you can test your image from 49 | ``` 50 | python3 demo.py 51 | ``` 52 | 53 | ### References 54 | * [EXTD: Extremely Tiny Face Detector via Iterative Filter Reuse](https://arxiv.org/abs/1906.06579) 55 | * [S3FD.pytorch](https://github.com/yxlijun/S3FD.pytorch) 56 | 57 | ### Citation 58 | ``` 59 | @article{yoo2019extd, 60 | title={EXTD: Extremely Tiny Face Detector via Iterative Filter Reuse}, 61 | author={Yoo, YoungJoon and Han, Dongyoon and Yun, Sangdoo}, 62 | journal={arXiv preprint arXiv:1906.06579}, 63 | year={2019} 64 | } 65 | ``` 66 | 67 | ### License 68 | ``` 69 | Copyright (c) 2019-present NAVER Corp. 70 | 71 | Permission is hereby granted, free of charge, to any person obtaining a copy 72 | of this software and associated documentation files (the "Software"), to deal 73 | in the Software without restriction, including without limitation the rights 74 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 75 | copies of the Software, and to permit persons to whom the Software is 76 | furnished to do so, subject to the following conditions: 77 | 78 | The above copyright notice and this permission notice shall be included in 79 | all copies or substantial portions of the Software. 80 | 81 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 82 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 83 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 84 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 85 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 86 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 87 | THE SOFTWARE 88 | ``` 89 | -------------------------------------------------------------------------------- /bbox_setup.py: -------------------------------------------------------------------------------- 1 | """ 2 | WiderFace evaluation code 3 | author: wondervictor 4 | mail: tianhengcheng@gmail.com 5 | copyright@wondervictor 6 | """ 7 | 8 | from distutils.core import setup, Extension 9 | from Cython.Build import cythonize 10 | import numpy 11 | 12 | package = Extension('bbox', ['./eval_tools/box_overlaps.pyx'], include_dirs=[numpy.get_include()]) 13 | setup(ext_modules=cythonize([package])) 14 | -------------------------------------------------------------------------------- /build/temp.linux-x86_64-3.5/eval_tools/box_overlaps.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/build/temp.linux-x86_64-3.5/eval_tools/box_overlaps.o -------------------------------------------------------------------------------- /data/config.py: -------------------------------------------------------------------------------- 1 | #-*- coding:utf-8 -*- 2 | 3 | from __future__ import division 4 | from __future__ import absolute_import 5 | from __future__ import print_function 6 | 7 | import os 8 | from easydict import EasyDict 9 | import numpy as np 10 | 11 | 12 | _C = EasyDict() 13 | cfg = _C 14 | # data augument config 15 | _C.expand_prob = 0.5 16 | _C.expand_max_ratio = 4 17 | _C.hue_prob = 0.5 18 | _C.hue_delta = 18 19 | _C.contrast_prob = 0.5 20 | _C.contrast_delta = 0.5 21 | _C.saturation_prob = 0.5 22 | _C.saturation_delta = 0.5 23 | _C.brightness_prob = 0.5 24 | _C.brightness_delta = 0.125 25 | _C.data_anchor_sampling_prob = 0.5 26 | _C.min_face_size = 6.0 27 | _C.apply_distort = True 28 | _C.apply_expand = False 29 | _C.img_mean = np.array([104., 117., 123.])[:, np.newaxis, np.newaxis].astype( 30 | 'float32') 31 | _C.resize_width = 640 32 | _C.resize_height = 640 33 | _C.scale = 1 / 127.0 34 | _C.anchor_sampling = True 35 | _C.filter_min_face = True 36 | 37 | # train config 38 | #_C.LR_STEPS = (120, 198, 250) 39 | _C.MAX_STEPS = 480000 40 | _C.LR_STEPS = (240000, 360000) 41 | _C.EPOCHES = 600 42 | 43 | # anchor config 44 | _C.FEATURE_MAPS = [160, 80, 40, 20, 10, 5] 45 | _C.INPUT_SIZE = 640 46 | _C.STEPS = [4, 8, 16, 32, 64, 128] 47 | _C.ANCHOR_SIZES = [16, 32, 64, 128, 256, 512] 48 | _C.CLIP = False 49 | _C.VARIANCE = [0.1, 0.2] 50 | 51 | # detection config 52 | _C.NMS_THRESH = 0.3 53 | _C.NMS_TOP_K = 5000 54 | _C.TOP_K = 750 55 | _C.CONF_THRESH = 0.05 56 | 57 | # loss config 58 | _C.NEG_POS_RATIOS = 3 59 | _C.NUM_CLASSES = 2 60 | _C.USE_NMS = True 61 | 62 | # dataset config 63 | _C.HOME = '/home/data/lj/' 64 | 65 | # hand config 66 | _C.HAND = EasyDict() 67 | _C.HAND.TRAIN_FILE = './data/hand_train.txt' 68 | _C.HAND.VAL_FILE = './data/hand_val.txt' 69 | _C.HAND.DIR = '/home/data/lj/egohands/' 70 | _C.HAND.OVERLAP_THRESH = 0.35 71 | 72 | # face config 73 | _C.FACE = EasyDict() 74 | _C.FACE.TRAIN_FILE = './data/face_train.txt' 75 | _C.FACE.VAL_FILE = './data/face_val.txt' 76 | _C.FACE.FDDB_DIR = '/media/yoo/Data/FDDB' 77 | _C.FACE.WIDER_DIR = '/media/yoo/Data/wider_face' 78 | _C.FACE.AFW_DIR = '/home/data/lj/AFW' 79 | _C.FACE.PASCAL_DIR = '/home/data/lj/PASCAL_FACE' 80 | _C.FACE.OVERLAP_THRESH = [0.1, 0.35, 0.5] 81 | 82 | # head config 83 | _C.HEAD = EasyDict() 84 | _C.HEAD.DIR = '/home/data/lj/VOCHead/' 85 | _C.HEAD.OVERLAP_THRESH = [0.1, 0.35, 0.5] 86 | -------------------------------------------------------------------------------- /data/egohand.py: -------------------------------------------------------------------------------- 1 | #-*- coding:utf-8 -*- 2 | 3 | from __future__ import absolute_import 4 | from __future__ import division 5 | from __future__ import print_function 6 | 7 | import torch 8 | from PIL import Image, ImageDraw 9 | import torch.utils.data as data 10 | import numpy as np 11 | import random 12 | from utils.augmentations import preprocess 13 | 14 | 15 | class HandDetection(data.Dataset): 16 | """docstring for WIDERDetection""" 17 | 18 | def __init__(self, list_file, mode='train'): 19 | super(HandDetection, self).__init__() 20 | self.mode = mode 21 | self.fnames = [] 22 | self.boxes = [] 23 | self.labels = [] 24 | 25 | with open(list_file) as f: 26 | lines = f.readlines() 27 | 28 | for line in lines: 29 | line = line.strip().split() 30 | num_faces = int(line[1]) 31 | box = [] 32 | label = [] 33 | for i in xrange(num_faces): 34 | xmin = float(line[2 + 4 * i]) 35 | ymin = float(line[3 + 4 * i]) 36 | xmax = float(line[4 + 4 * i]) 37 | ymax = float(line[5 + 4 * i]) 38 | box.append([xmin, ymin, xmax, ymax]) 39 | label.append(1) 40 | self.fnames.append(line[0]) 41 | self.boxes.append(box) 42 | self.labels.append(label) 43 | 44 | self.num_samples = len(self.boxes) 45 | 46 | def __len__(self): 47 | return self.num_samples 48 | 49 | def __getitem__(self, index): 50 | img, target, h, w = self.pull_item(index) 51 | return img, target 52 | 53 | def pull_item(self, index): 54 | while True: 55 | image_path = self.fnames[index] 56 | img = Image.open(image_path) 57 | if img.mode == 'L': 58 | img = img.convert('RGB') 59 | 60 | im_width, im_height = img.size 61 | boxes = self.annotransform( 62 | np.array(self.boxes[index]), im_width, im_height) 63 | label = np.array(self.labels[index]) 64 | bbox_labels = np.hstack((label[:, np.newaxis], boxes)).tolist() 65 | img, sample_labels = preprocess( 66 | img, bbox_labels, self.mode, image_path) 67 | sample_labels = np.array(sample_labels) 68 | if len(sample_labels) > 0: 69 | target = np.hstack( 70 | (sample_labels[:, 1:], sample_labels[:, 0][:, np.newaxis])) 71 | 72 | assert (target[:, 2] > target[:, 0]).any() 73 | assert (target[:, 3] > target[:, 1]).any() 74 | break 75 | else: 76 | index = random.randrange(0, self.num_samples) 77 | 78 | ''' 79 | #img = Image.fromarray(img) 80 | draw = ImageDraw.Draw(img) 81 | w,h = img.size 82 | for bbox in target: 83 | bbox = (bbox[:-1] * np.array([w, h, w, h])).tolist() 84 | 85 | draw.rectangle(bbox,outline='red') 86 | img.show() 87 | ''' 88 | return torch.from_numpy(img), target, im_height, im_width 89 | 90 | 91 | def annotransform(self, boxes, im_width, im_height): 92 | boxes[:, 0] /= im_width 93 | boxes[:, 1] /= im_height 94 | boxes[:, 2] /= im_width 95 | boxes[:, 3] /= im_height 96 | return boxes 97 | 98 | 99 | def pull_image(self,index): 100 | img_path = self.fnames[index] 101 | img = Image.open(img_path) 102 | if img.mode=='L': 103 | img.convert('RGB') 104 | img = np.array(img) 105 | return img 106 | 107 | 108 | if __name__ == '__main__': 109 | from data.config import cfg 110 | dataset = HandDetection(cfg.TRAIN_FILE) 111 | #for i in range(len(dataset)): 112 | dataset.pull_item(2) 113 | -------------------------------------------------------------------------------- /data/factory.py: -------------------------------------------------------------------------------- 1 | #-*- coding:utf-8 -*- 2 | 3 | from __future__ import division 4 | from __future__ import absolute_import 5 | from __future__ import print_function 6 | 7 | 8 | from .egohand import HandDetection 9 | from .widerface import WIDERDetection 10 | from .vochead import VOCDetection, VOCAnnotationTransform 11 | from .config import cfg 12 | 13 | import torch 14 | 15 | 16 | def dataset_factory(dataset): 17 | if dataset == 'face': 18 | train_dataset = WIDERDetection(cfg.FACE.TRAIN_FILE, mode='train') 19 | val_dataset = WIDERDetection(cfg.FACE.VAL_FILE, mode='val') 20 | if dataset == 'hand': 21 | train_dataset = WIDERDetection(cfg.HAND.TRAIN_FILE, mode='train') 22 | val_dataset = WIDERDetection(cfg.HAND.VAL_FILE, mode='val') 23 | if dataset == 'head': 24 | train_dataset = VOCDetection(cfg.HEAD.DIR, image_sets=[ 25 | ('PartA', 'trainval'), ('PartB', 'trainval')], 26 | target_transform=VOCAnnotationTransform(), 27 | mode='train', 28 | dataset_name='VOCPartAB') 29 | val_dataset = VOCDetection(cfg.HEAD.DIR, image_sets=[('PartA', 'test'), ('PartB', 'test')], 30 | target_transform=VOCAnnotationTransform(), 31 | mode='test', 32 | dataset_name='VOCPartAB') 33 | return train_dataset, val_dataset 34 | 35 | 36 | def detection_collate(batch): 37 | """Custom collate fn for dealing with batches of images that have a different 38 | number of associated object annotations (bounding boxes). 39 | 40 | Arguments: 41 | batch: (tuple) A tuple of tensor images and lists of annotations 42 | 43 | Return: 44 | A tuple containing: 45 | 1) (tensor) batch of images stacked on their 0 dim 46 | 2) (list of tensors) annotations for a given image are stacked on 47 | 0 dim 48 | """ 49 | targets = [] 50 | imgs = [] 51 | for sample in batch: 52 | imgs.append(sample[0]) 53 | targets.append(torch.FloatTensor(sample[1])) 54 | return torch.stack(imgs, 0), targets 55 | -------------------------------------------------------------------------------- /data/vochead.py: -------------------------------------------------------------------------------- 1 | """VOC Dataset Classes 2 | 3 | Original author: Francisco Massa 4 | https://github.com/fmassa/vision/blob/voc_dataset/torchvision/datasets/voc.py 5 | 6 | Updated by: Ellis Brown, Max deGroot 7 | """ 8 | from __future__ import division 9 | from __future__ import print_function 10 | from __future__ import absolute_import 11 | 12 | import os.path as osp 13 | import sys 14 | import torch 15 | import torch.utils.data as data 16 | import cv2 17 | import numpy as np 18 | import random 19 | 20 | if sys.version_info[0] == 2: 21 | import xml.etree.cElementTree as ET 22 | else: 23 | import xml.etree.ElementTree as ET 24 | from utils.augmentations import preprocess 25 | from PIL import ImageDraw, Image 26 | 27 | 28 | class VOCAnnotationTransform(object): 29 | """Transforms a VOC annotation into a Tensor of bbox coords and label index 30 | Initilized with a dictionary lookup of classnames to indexes 31 | 32 | Arguments: 33 | class_to_ind (dict, optional): dictionary lookup of classnames -> indexes 34 | (default: alphabetic indexing of VOC's 20 classes) 35 | keep_difficult (bool, optional): keep difficult instances or not 36 | (default: False) 37 | height (int): height 38 | width (int): width 39 | """ 40 | 41 | def __init__(self, keep_difficult=False): 42 | self.keep_difficult = keep_difficult 43 | 44 | def __call__(self, target, width, height): 45 | """ 46 | Arguments: 47 | target (annotation) : the target annotation to be made usable 48 | will be an ET.Element 49 | Returns: 50 | a list containing lists of bounding boxes [bbox coords, class name] 51 | """ 52 | res = [] 53 | for obj in target.iter('object'): 54 | difficult = int(obj.find('difficult').text) == 1 55 | if not self.keep_difficult and difficult: 56 | continue 57 | name = obj.find('name').text.lower().strip() 58 | bbox = obj.find('bndbox') 59 | 60 | pts = ['xmin', 'ymin', 'xmax', 'ymax'] 61 | bndbox = [1] 62 | for i, pt in enumerate(pts): 63 | cur_pt = int(bbox.find(pt).text) - 1 64 | # scale height or width 65 | cur_pt = cur_pt / width if i % 2 == 0 else cur_pt / height 66 | bndbox.append(cur_pt) 67 | #label_idx = 1 68 | # bndbox.append(label_idx) 69 | res += [bndbox] # [xmin, ymin, xmax, ymax, label_ind] 70 | # img_id = target.find('filename').text[:-4] 71 | return res # [[xmin, ymin, xmax, ymax, label_ind], ... ] 72 | 73 | 74 | class VOCDetection(data.Dataset): 75 | """VOC Detection Dataset Object 76 | 77 | input is image, target is annotation 78 | 79 | Arguments: 80 | root (string): filepath to VOCdevkit folder. 81 | image_set (string): imageset to use (eg. 'train', 'val', 'test') 82 | transform (callable, optional): transformation to perform on the 83 | input image 84 | target_transform (callable, optional): transformation to perform on the 85 | target `annotation` 86 | (eg: take in caption string, return tensor of word indices) 87 | dataset_name (string, optional): which dataset to load 88 | (default: 'VOC2007') 89 | """ 90 | 91 | def __init__(self, root, 92 | image_sets=[('PartA', 'trainval'), 93 | ('PartB', 'trainval')], 94 | target_transform=VOCAnnotationTransform(), 95 | mode='train', 96 | dataset_name='VOCPartAB'): 97 | 98 | self.root = root 99 | self.mode = mode 100 | self.image_set = image_sets 101 | self.target_transform = target_transform 102 | self.name = dataset_name 103 | self._annopath = osp.join('%s', 'Annotations', '%s.xml') 104 | self._imgpath = osp.join('%s', 'JPEGImages', '%s.jpg') 105 | self.ids = list() 106 | for (part, name) in image_sets: 107 | rootpath = osp.join(self.root, 'VOC' + part) 108 | for line in open(osp.join(rootpath, 'ImageSets', 'Main', name + '.txt')): 109 | self.ids.append((rootpath, line.strip())) 110 | 111 | def __getitem__(self, index): 112 | im, gt = self.pull_item(index) 113 | 114 | return im, gt 115 | 116 | def __len__(self): 117 | return len(self.ids) 118 | 119 | def pull_item(self, index): 120 | while True: 121 | img_id = self.ids[index] 122 | img_path = self._imgpath % img_id 123 | target = ET.parse(self._annopath % img_id).getroot() 124 | img = Image.open(img_path) 125 | 126 | if img.mode == 'L': 127 | img = img.convert('RGB') 128 | 129 | width, height = img.size 130 | 131 | if self.target_transform is not None: 132 | target = self.target_transform(target, width, height) 133 | bbox_labels = target 134 | target = np.array(target) 135 | if target.ndim!=2: 136 | index = random.randrange(0, len(self.ids)) 137 | continue 138 | img, sample_labels = preprocess( 139 | img, bbox_labels, self.mode, img_path) 140 | sample_labels = np.array(sample_labels) 141 | if len(sample_labels) > 0: 142 | target = np.hstack( 143 | (sample_labels[:, 1:], sample_labels[:, 0][:, np.newaxis])) 144 | 145 | assert (target[:, 2] > target[:, 0]).any() 146 | assert (target[:, 3] > target[:, 1]).any() 147 | break 148 | else: 149 | index = random.randrange(0, len(self.ids)) 150 | 151 | return torch.from_numpy(img), target 152 | 153 | def pull_image(self, index): 154 | '''Returns the original image object at index in PIL form 155 | 156 | Note: not using self.__getitem__(), as any transformations passed in 157 | could mess up this functionality. 158 | 159 | Argument: 160 | index (int): index of img to show 161 | Return: 162 | PIL img 163 | ''' 164 | img_id = self.ids[index] 165 | img_path = self._imgpath % img_id 166 | img = Image.open(img_path) 167 | if img.mode=='L': 168 | img.convert('RGB') 169 | img = np.array(img) 170 | return img 171 | 172 | def pull_anno(self, index): 173 | '''Returns the original annotation of image at index 174 | 175 | Note: not using self.__getitem__(), as any transformations passed in 176 | could mess up this functionality. 177 | 178 | Argument: 179 | index (int): index of img to get annotation of 180 | Return: 181 | list: [img_id, [(label, bbox coords),...]] 182 | eg: ('001718', [('dog', (96, 13, 438, 332))]) 183 | ''' 184 | img_id = self.ids[index] 185 | anno = ET.parse(self._annopath % img_id).getroot() 186 | gt = self.target_transform(anno, 1, 1) 187 | return img_id[1], gt 188 | 189 | def pull_tensor(self, index): 190 | '''Returns the original image at an index in tensor form 191 | 192 | Note: not using self.__getitem__(), as any transformations passed in 193 | could mess up this functionality. 194 | 195 | Argument: 196 | index (int): index of img to show 197 | Return: 198 | tensorized version of img, squeezed 199 | ''' 200 | return torch.Tensor(self.pull_image(index)).unsqueeze_(0) 201 | 202 | 203 | if __name__ == '__main__': 204 | from config import cfg 205 | dataset = VOCDetection(cfg.HEAD.DIR) 206 | dataset.pull_item(0) 207 | -------------------------------------------------------------------------------- /data/widerface.py: -------------------------------------------------------------------------------- 1 | #-*- coding:utf-8 -*- 2 | 3 | from __future__ import absolute_import 4 | from __future__ import division 5 | from __future__ import print_function 6 | 7 | import torch 8 | from PIL import Image, ImageDraw 9 | import torch.utils.data as data 10 | import numpy as np 11 | import random 12 | from utils.augmentations import preprocess 13 | 14 | 15 | class WIDERDetection(data.Dataset): 16 | """docstring for WIDERDetection""" 17 | 18 | def __init__(self, list_file, mode='train'): 19 | super(WIDERDetection, self).__init__() 20 | self.mode = mode 21 | self.fnames = [] 22 | self.boxes = [] 23 | self.labels = [] 24 | 25 | with open(list_file) as f: 26 | lines = f.readlines() 27 | 28 | for line in lines: 29 | line = line.strip().split() 30 | num_faces = int(line[1]) 31 | box = [] 32 | label = [] 33 | for i in range(num_faces): 34 | x = float(line[2 + 5 * i]) 35 | y = float(line[3 + 5 * i]) 36 | w = float(line[4 + 5 * i]) 37 | h = float(line[5 + 5 * i]) 38 | c = int(line[6 + 5 * i]) 39 | if w <= 0 or h <= 0: 40 | continue 41 | box.append([x, y, x + w, y + h]) 42 | label.append(c) 43 | if len(box) > 0: 44 | self.fnames.append(line[0]) 45 | self.boxes.append(box) 46 | self.labels.append(label) 47 | 48 | self.num_samples = len(self.boxes) 49 | 50 | def __len__(self): 51 | return self.num_samples 52 | 53 | def __getitem__(self, index): 54 | img, target, h, w = self.pull_item(index) 55 | return img, target 56 | 57 | def pull_item(self, index): 58 | while True: 59 | image_path = self.fnames[index] 60 | img = Image.open(image_path) 61 | if img.mode == 'L': 62 | img = img.convert('RGB') 63 | 64 | im_width, im_height = img.size 65 | boxes = self.annotransform( 66 | np.array(self.boxes[index]), im_width, im_height) 67 | label = np.array(self.labels[index]) 68 | bbox_labels = np.hstack((label[:, np.newaxis], boxes)).tolist() 69 | img, sample_labels = preprocess( 70 | img, bbox_labels, self.mode, image_path) 71 | sample_labels = np.array(sample_labels) 72 | if len(sample_labels) > 0: 73 | target = np.hstack( 74 | (sample_labels[:, 1:], sample_labels[:, 0][:, np.newaxis])) 75 | 76 | assert (target[:, 2] > target[:, 0]).any() 77 | assert (target[:, 3] > target[:, 1]).any() 78 | break 79 | else: 80 | index = random.randrange(0, self.num_samples) 81 | 82 | 83 | #img = Image.fromarray(img) 84 | ''' 85 | draw = ImageDraw.Draw(img) 86 | w,h = img.size 87 | for bbox in sample_labels: 88 | bbox = (bbox[1:] * np.array([w, h, w, h])).tolist() 89 | 90 | draw.rectangle(bbox,outline='red') 91 | img.save('image.jpg') 92 | ''' 93 | return torch.from_numpy(img), target, im_height, im_width 94 | 95 | 96 | def annotransform(self, boxes, im_width, im_height): 97 | boxes[:, 0] /= im_width 98 | boxes[:, 1] /= im_height 99 | boxes[:, 2] /= im_width 100 | boxes[:, 3] /= im_height 101 | return boxes 102 | 103 | 104 | def detection_collate(batch): 105 | """Custom collate fn for dealing with batches of images that have a different 106 | number of associated object annotations (bounding boxes). 107 | 108 | Arguments: 109 | batch: (tuple) A tuple of tensor images and lists of annotations 110 | 111 | Return: 112 | A tuple containing: 113 | 1) (tensor) batch of images stacked on their 0 dim 114 | 2) (list of tensors) annotations for a given image are stacked on 115 | 0 dim 116 | """ 117 | targets = [] 118 | imgs = [] 119 | for sample in batch: 120 | imgs.append(sample[0]) 121 | targets.append(torch.FloatTensor(sample[1])) 122 | return torch.stack(imgs, 0), targets 123 | 124 | 125 | if __name__ == '__main__': 126 | from config import cfg 127 | dataset = WIDERDetection(cfg.FACE.TRAIN_FILE) 128 | #for i in range(len(dataset)): 129 | dataset.pull_item(14) 130 | -------------------------------------------------------------------------------- /demo.py: -------------------------------------------------------------------------------- 1 | ''' 2 | EXTD Copyright (c) 2019-present NAVER Corp. MIT License 3 | ''' 4 | #-*- coding:utf-8 -*- 5 | 6 | from __future__ import division 7 | from __future__ import absolute_import 8 | from __future__ import print_function 9 | 10 | import os 11 | import torch 12 | import argparse 13 | import torch.nn as nn 14 | import torch.utils.data as data 15 | import torch.backends.cudnn as cudnn 16 | import torchvision.transforms as transforms 17 | 18 | import cv2 19 | import time 20 | import numpy as np 21 | from PIL import Image 22 | 23 | from data.config import cfg 24 | from EXTD_64 import build_extd 25 | from torch.autograd import Variable 26 | from utils.augmentations import to_chw_bgr 27 | 28 | import tqdm 29 | 30 | 31 | parser = argparse.ArgumentParser(description='EXTD demo') 32 | parser.add_argument('--save_dir', type=str, default='tmp/', 33 | help='Directory for detect result') 34 | parser.add_argument('--model', type=str, 35 | default='weights/EXTD_64.pth', help='trained model') 36 | parser.add_argument('--thresh', default=0.6, type=float, 37 | help='Final confidence threshold') 38 | args = parser.parse_args() 39 | 40 | 41 | if not os.path.exists(args.save_dir): 42 | os.makedirs(args.save_dir) 43 | 44 | use_cuda = torch.cuda.is_available() 45 | 46 | if use_cuda: 47 | torch.set_default_tensor_type('torch.cuda.FloatTensor') 48 | else: 49 | torch.set_default_tensor_type('torch.FloatTensor') 50 | 51 | 52 | def detect(net, img_path, thresh, wid, hei): 53 | #img = cv2.imread(img_path, cv2.IMREAD_COLOR) 54 | img = Image.open(img_path) 55 | if img.mode == 'L': 56 | img = img.convert('RGB') 57 | 58 | img = np.array(img) 59 | height, width, _ = img.shape 60 | 61 | 62 | if wid > 0 and hei > 0: 63 | image = cv2.resize(img, (wid, hei)) 64 | else: 65 | max_im_shrink = np.sqrt(1700 * 1200 / (img.shape[0] * img.shape[1])) 66 | image = cv2.resize(img, None, None, fx=max_im_shrink, fy=max_im_shrink, interpolation=cv2.INTER_LINEAR) 67 | 68 | 69 | x = to_chw_bgr(image) 70 | x = x.astype('float32') 71 | x -= cfg.img_mean 72 | x = x[[2, 1, 0], :, :] 73 | 74 | x = Variable(torch.from_numpy(x).unsqueeze(0)) 75 | if use_cuda: 76 | x = x.cuda() 77 | 78 | 79 | with torch.no_grad(): 80 | 81 | t1 = time.time() 82 | 83 | y = net(x) 84 | detections = y.data 85 | scale = torch.Tensor([img.shape[1], img.shape[0], 86 | img.shape[1], img.shape[0]]) 87 | 88 | img = cv2.imread(img_path, cv2.IMREAD_COLOR) 89 | 90 | for i in range(detections.size(1)): 91 | j = 0 92 | while detections[0, i, j, 0] >= thresh: 93 | score = detections[0, i, j, 0] 94 | pt = (detections[0, i, j, 1:] * scale).cpu().numpy() 95 | left_up, right_bottom = (pt[0], pt[1]), (pt[2], pt[3]) 96 | j += 1 97 | cv2.rectangle(img, left_up, right_bottom, (0, 0, 255), 2) 98 | conf = "{:.3f}".format(score) 99 | point = (int(left_up[0]), int(left_up[1] - 5)) 100 | # cv2.putText(img, conf, point, cv2.FONT_HERSHEY_COMPLEX, 101 | # 0.6, (0, 255, 0), 1) 102 | 103 | t2 = time.time() 104 | 105 | 106 | 107 | #print('detect:{} timer:{}'.format(img_path, t2 - t1)) 108 | 109 | cv2.imwrite(os.path.join(args.save_dir, os.path.basename(img_path)), img) 110 | 111 | return t2-t1 112 | 113 | 114 | if __name__ == '__main__': 115 | net = build_extd('test', cfg.NUM_CLASSES) 116 | net.load_state_dict(torch.load(args.model)) 117 | net.eval() 118 | 119 | if use_cuda: 120 | net.cuda() 121 | cudnn.benckmark = True 122 | 123 | img_path = './img' 124 | img_list = [os.path.join(img_path, x) 125 | for x in os.listdir(img_path) if x.endswith('jpg')] 126 | 127 | for path in img_list: 128 | dt = detect(net, path, args.thresh, -1, -1) 129 | 130 | ''' 131 | file = open('time_check.txt', 'w') 132 | 133 | 134 | for ind in range(51): 135 | t = 0 136 | for rnd in tqdm.tqdm(range(1500)): 137 | img_path = './img' 138 | img_list = [os.path.join(img_path, x) 139 | for x in os.listdir(img_path) if x.endswith('jpg')] 140 | 141 | for path in img_list: 142 | dt = detect(net, path, args.thresh, 280 + 40 * ind, 280 + 40 * ind) 143 | if rnd>500: 144 | t += dt 145 | 146 | 147 | 148 | print('{} {}'.format(280 + 40 * ind, t/1000)) 149 | file.write('{} {}\n'.format(280 + 40 * ind, t/1000)) 150 | 151 | file.close() 152 | ''' 153 | -------------------------------------------------------------------------------- /eval_tools/box_overlaps.pyx: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------- 2 | # Fast R-CNN 3 | # Copyright (c) 2015 Microsoft 4 | # Licensed under The MIT License [see LICENSE for details] 5 | # Written by Sergey Karayev 6 | # -------------------------------------------------------- 7 | 8 | cimport cython 9 | import numpy as np 10 | cimport numpy as np 11 | 12 | DTYPE = np.float 13 | ctypedef np.float_t DTYPE_t 14 | 15 | def bbox_overlaps( 16 | np.ndarray[DTYPE_t, ndim=2] boxes, 17 | np.ndarray[DTYPE_t, ndim=2] query_boxes): 18 | """ 19 | Parameters 20 | ---------- 21 | boxes: (N, 4) ndarray of float 22 | query_boxes: (K, 4) ndarray of float 23 | Returns 24 | ------- 25 | overlaps: (N, K) ndarray of overlap between boxes and query_boxes 26 | """ 27 | cdef unsigned int N = boxes.shape[0] 28 | cdef unsigned int K = query_boxes.shape[0] 29 | cdef np.ndarray[DTYPE_t, ndim=2] overlaps = np.zeros((N, K), dtype=DTYPE) 30 | cdef DTYPE_t iw, ih, box_area 31 | cdef DTYPE_t ua 32 | cdef unsigned int k, n 33 | for k in range(K): 34 | box_area = ( 35 | (query_boxes[k, 2] - query_boxes[k, 0] + 1) * 36 | (query_boxes[k, 3] - query_boxes[k, 1] + 1) 37 | ) 38 | for n in range(N): 39 | iw = ( 40 | min(boxes[n, 2], query_boxes[k, 2]) - 41 | max(boxes[n, 0], query_boxes[k, 0]) + 1 42 | ) 43 | if iw > 0: 44 | ih = ( 45 | min(boxes[n, 3], query_boxes[k, 3]) - 46 | max(boxes[n, 1], query_boxes[k, 1]) + 1 47 | ) 48 | if ih > 0: 49 | ua = float( 50 | (boxes[n, 2] - boxes[n, 0] + 1) * 51 | (boxes[n, 3] - boxes[n, 1] + 1) + 52 | box_area - iw * ih 53 | ) 54 | overlaps[n, k] = iw * ih / ua 55 | return overlaps -------------------------------------------------------------------------------- /eval_tools/evaluation.py: -------------------------------------------------------------------------------- 1 | """ 2 | WiderFace evaluation code 3 | author: wondervictor 4 | mail: tianhengcheng@gmail.com 5 | copyright@wondervictor 6 | """ 7 | 8 | import os 9 | import tqdm 10 | import pickle 11 | import argparse 12 | import numpy as np 13 | from scipy.io import loadmat 14 | from scipy.io import savemat 15 | 16 | from bbox import bbox_overlaps 17 | #from IPython import embed 18 | 19 | 20 | def get_gt_boxes(gt_dir): 21 | """ gt dir: (wider_face_val.mat, wider_easy_val.mat, wider_medium_val.mat, wider_hard_val.mat)""" 22 | 23 | gt_mat = loadmat(os.path.join(gt_dir, 'wider_face_val.mat')) 24 | hard_mat = loadmat(os.path.join(gt_dir, 'wider_hard_val.mat')) 25 | medium_mat = loadmat(os.path.join(gt_dir, 'wider_medium_val.mat')) 26 | easy_mat = loadmat(os.path.join(gt_dir, 'wider_easy_val.mat')) 27 | 28 | facebox_list = gt_mat['face_bbx_list'] 29 | event_list = gt_mat['event_list'] 30 | file_list = gt_mat['file_list'] 31 | 32 | hard_gt_list = hard_mat['gt_list'] 33 | medium_gt_list = medium_mat['gt_list'] 34 | easy_gt_list = easy_mat['gt_list'] 35 | 36 | return facebox_list, event_list, file_list, hard_gt_list, medium_gt_list, easy_gt_list 37 | 38 | 39 | def get_gt_boxes_from_txt(gt_path, cache_dir): 40 | 41 | cache_file = os.path.join(cache_dir, 'gt_cache.pkl') 42 | if os.path.exists(cache_file): 43 | f = open(cache_file, 'rb') 44 | boxes = pickle.load(f) 45 | f.close() 46 | return boxes 47 | 48 | f = open(gt_path, 'r') 49 | state = 0 50 | lines = f.readlines() 51 | lines = list(map(lambda x: x.rstrip('\r\n'), lines)) 52 | boxes = {} 53 | print(len(lines)) 54 | f.close() 55 | current_boxes = [] 56 | current_name = None 57 | for line in lines: 58 | if state == 0 and '--' in line: 59 | state = 1 60 | current_name = line 61 | continue 62 | if state == 1: 63 | state = 2 64 | continue 65 | 66 | if state == 2 and '--' in line: 67 | state = 1 68 | boxes[current_name] = np.array(current_boxes).astype('float32') 69 | current_name = line 70 | current_boxes = [] 71 | continue 72 | 73 | if state == 2: 74 | box = [float(x) for x in line.split(' ')[:4]] 75 | current_boxes.append(box) 76 | continue 77 | 78 | f = open(cache_file, 'wb') 79 | pickle.dump(boxes, f) 80 | f.close() 81 | return boxes 82 | 83 | 84 | def read_pred_file(filepath): 85 | 86 | with open(filepath, 'r') as f: 87 | lines = f.readlines() 88 | img_file = lines[0].rstrip('\n\r') 89 | lines = lines[2:] 90 | 91 | boxes = np.array(list(map(lambda x: [float(a) for a in x.rstrip('\r\n').split(' ')], lines))).astype('float') 92 | return img_file.split('/')[-1], boxes 93 | 94 | 95 | def get_preds(pred_dir): 96 | events = os.listdir(pred_dir) 97 | boxes = dict() 98 | pbar = tqdm.tqdm(events) 99 | 100 | for event in pbar: 101 | pbar.set_description('Reading Predictions ') 102 | event_dir = os.path.join(pred_dir, event) 103 | event_images = os.listdir(event_dir) 104 | current_event = dict() 105 | for imgtxt in event_images: 106 | imgname, _boxes = read_pred_file(os.path.join(event_dir, imgtxt)) 107 | current_event[imgname.rstrip('.jpg')] = _boxes 108 | boxes[event] = current_event 109 | return boxes 110 | 111 | 112 | def norm_score(pred): 113 | """ norm score 114 | pred {key: [[x1,y1,x2,y2,s]]} 115 | """ 116 | 117 | max_score = 0 118 | min_score = 1 119 | 120 | for _, k in pred.items(): 121 | for _, v in k.items(): 122 | if len(v) == 0: 123 | continue 124 | _min = np.min(v[:, -1]) 125 | _max = np.max(v[:, -1]) 126 | max_score = max(_max, max_score) 127 | min_score = min(_min, min_score) 128 | 129 | diff = max_score - min_score 130 | for _, k in pred.items(): 131 | for _, v in k.items(): 132 | if len(v) == 0: 133 | continue 134 | v[:, -1] = (v[:, -1] - min_score)/diff 135 | 136 | 137 | def image_eval(pred, gt, ignore, iou_thresh): 138 | """ single image evaluation 139 | pred: Nx5 140 | gt: Nx4 141 | ignore: 142 | """ 143 | 144 | _pred = pred.copy() 145 | _gt = gt.copy() 146 | pred_recall = np.zeros(_pred.shape[0]) 147 | recall_list = np.zeros(_gt.shape[0]) 148 | proposal_list = np.ones(_pred.shape[0]) 149 | 150 | _pred[:, 2] = _pred[:, 2] + _pred[:, 0] 151 | _pred[:, 3] = _pred[:, 3] + _pred[:, 1] 152 | _gt[:, 2] = _gt[:, 2] + _gt[:, 0] 153 | _gt[:, 3] = _gt[:, 3] + _gt[:, 1] 154 | 155 | overlaps = bbox_overlaps(_pred[:, :4], _gt) 156 | 157 | for h in range(_pred.shape[0]): 158 | 159 | gt_overlap = overlaps[h] 160 | max_overlap, max_idx = gt_overlap.max(), gt_overlap.argmax() 161 | if max_overlap >= iou_thresh: 162 | if ignore[max_idx] == 0: 163 | recall_list[max_idx] = -1 164 | proposal_list[h] = -1 165 | elif recall_list[max_idx] == 0: 166 | recall_list[max_idx] = 1 167 | 168 | r_keep_index = np.where(recall_list == 1)[0] 169 | pred_recall[h] = len(r_keep_index) 170 | return pred_recall, proposal_list 171 | 172 | 173 | def img_pr_info(thresh_num, pred_info, proposal_list, pred_recall): 174 | pr_info = np.zeros((thresh_num, 2)).astype('float') 175 | for t in range(thresh_num): 176 | 177 | thresh = 1 - (t+1)/thresh_num 178 | r_index = np.where(pred_info[:, 4] >= thresh)[0] 179 | if len(r_index) == 0: 180 | pr_info[t, 0] = 0 181 | pr_info[t, 1] = 0 182 | else: 183 | r_index = r_index[-1] 184 | p_index = np.where(proposal_list[:r_index+1] == 1)[0] 185 | pr_info[t, 0] = len(p_index) 186 | pr_info[t, 1] = pred_recall[r_index] 187 | return pr_info 188 | 189 | 190 | def dataset_pr_info(thresh_num, pr_curve, count_face): 191 | _pr_curve = np.zeros((thresh_num, 2)) 192 | for i in range(thresh_num): 193 | _pr_curve[i, 0] = pr_curve[i, 1] / pr_curve[i, 0] 194 | _pr_curve[i, 1] = pr_curve[i, 1] / count_face 195 | return _pr_curve 196 | 197 | 198 | def voc_ap(rec, prec): 199 | 200 | # correct AP calculation 201 | # first append sentinel values at the end 202 | mrec = np.concatenate(([0.], rec, [1.])) 203 | mpre = np.concatenate(([0.], prec, [0.])) 204 | 205 | # compute the precision envelope 206 | for i in range(mpre.size - 1, 0, -1): 207 | mpre[i - 1] = np.maximum(mpre[i - 1], mpre[i]) 208 | 209 | # to calculate area under PR curve, look for points 210 | # where X axis (recall) changes value 211 | i = np.where(mrec[1:] != mrec[:-1])[0] 212 | 213 | # and sum (\Delta recall) * prec 214 | ap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1]) 215 | return ap 216 | 217 | 218 | def evaluation(pred='./eval_tools/s3fd_val', 219 | gt_path='./eval_tools/ground_truth/', iou_thresh=0.5): 220 | pred = get_preds(pred) 221 | norm_score(pred) 222 | facebox_list, event_list, file_list, hard_gt_list, medium_gt_list, easy_gt_list = get_gt_boxes(gt_path) 223 | event_num = len(event_list) 224 | thresh_num = 1000 225 | settings = ['easy', 'medium', 'hard'] 226 | setting_gts = [easy_gt_list, medium_gt_list, hard_gt_list] 227 | aps = [] 228 | for setting_id in range(3): 229 | # different setting 230 | gt_list = setting_gts[setting_id] 231 | count_face = 0 232 | pr_curve = np.zeros((thresh_num, 2)).astype('float') 233 | # [hard, medium, easy] 234 | pbar = tqdm.tqdm(range(event_num)) 235 | for i in pbar: 236 | pbar.set_description('Processing {}'.format(settings[setting_id])) 237 | event_name = str(event_list[i][0][0]) 238 | img_list = file_list[i][0] 239 | try: 240 | pred_list = pred[event_name] 241 | sub_gt_list = gt_list[i][0] 242 | # img_pr_info_list = np.zeros((len(img_list), thresh_num, 2)) 243 | gt_bbx_list = facebox_list[i][0] 244 | 245 | for j in range(len(img_list)): 246 | pred_info = pred_list[str(img_list[j][0][0])] 247 | 248 | gt_boxes = gt_bbx_list[j][0].astype('float') 249 | keep_index = sub_gt_list[j][0] 250 | count_face += len(keep_index) 251 | 252 | if len(gt_boxes) == 0 or len(pred_info) == 0: 253 | continue 254 | ignore = np.zeros(gt_boxes.shape[0]) 255 | if len(keep_index) != 0: 256 | ignore[keep_index - 1] = 1 257 | pred_recall, proposal_list = image_eval(pred_info, gt_boxes, ignore, iou_thresh) 258 | 259 | _img_pr_info = img_pr_info(thresh_num, pred_info, proposal_list, pred_recall) 260 | 261 | pr_curve += _img_pr_info 262 | except: 263 | print('no list') 264 | 265 | 266 | pr_curve = dataset_pr_info(thresh_num, pr_curve, count_face) 267 | 268 | propose = pr_curve[:, 0] 269 | recall = pr_curve[:, 1] 270 | 271 | ap = voc_ap(recall, propose) 272 | aps.append(ap) 273 | 274 | # save to the wider format 275 | savedict = {} 276 | savedict['legend_name'] = 'ETF' 277 | savedict['pr_curve'] = pr_curve 278 | 279 | savename = 'wider_pr_info_ETF_'+settings[setting_id]+'_val.mat' 280 | savemat(savename, savedict) 281 | 282 | 283 | 284 | print("==================== Results ====================") 285 | print("Easy Val AP: {}".format(aps[0])) 286 | print("Medium Val AP: {}".format(aps[1])) 287 | print("Hard Val AP: {}".format(aps[2])) 288 | print("=================================================") 289 | 290 | 291 | if __name__ == '__main__': 292 | 293 | parser = argparse.ArgumentParser() 294 | parser.add_argument('-p', '--pred') 295 | parser.add_argument('-g', '--gt', default='./ground_truth/') 296 | 297 | args = parser.parse_args() 298 | evaluation() 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | -------------------------------------------------------------------------------- /eval_tools/ground_truth/wider_easy_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/ground_truth/wider_easy_val.mat -------------------------------------------------------------------------------- /eval_tools/ground_truth/wider_face_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/ground_truth/wider_face_val.mat -------------------------------------------------------------------------------- /eval_tools/ground_truth/wider_hard_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/ground_truth/wider_hard_val.mat -------------------------------------------------------------------------------- /eval_tools/ground_truth/wider_medium_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/ground_truth/wider_medium_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_ext/acf/wider_pr_info_acf_easy.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_ext/acf/wider_pr_info_acf_easy.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_ext/acf/wider_pr_info_acf_hard.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_ext/acf/wider_pr_info_acf_hard.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_ext/acf/wider_pr_info_acf_medium.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_ext/acf/wider_pr_info_acf_medium.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_ext/dpm/wider_pr_info_dpm_easy.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_ext/dpm/wider_pr_info_dpm_easy.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_ext/dpm/wider_pr_info_dpm_hard.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_ext/dpm/wider_pr_info_dpm_hard.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_ext/dpm/wider_pr_info_dpm_medium.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_ext/dpm/wider_pr_info_dpm_medium.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_ext/faceness/wider_pr_info_faceness_easy.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_ext/faceness/wider_pr_info_faceness_easy.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_ext/faceness/wider_pr_info_faceness_hard.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_ext/faceness/wider_pr_info_faceness_hard.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_ext/faceness/wider_pr_info_faceness_medium.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_ext/faceness/wider_pr_info_faceness_medium.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_ext/vj/wider_pr_info_vj_easy.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_ext/vj/wider_pr_info_vj_easy.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_ext/vj/wider_pr_info_vj_hard.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_ext/vj/wider_pr_info_vj_hard.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_ext/vj/wider_pr_info_vj_medium.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_ext/vj/wider_pr_info_vj_medium.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/DSFD/wider_pr_info_DSFD_easy.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/DSFD/wider_pr_info_DSFD_easy.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/DSFD/wider_pr_info_DSFD_hard.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/DSFD/wider_pr_info_DSFD_hard.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/DSFD/wider_pr_info_DSFD_medium.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/DSFD/wider_pr_info_DSFD_medium.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/FAN/wider_pr_info_FAN_easy.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/FAN/wider_pr_info_FAN_easy.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/FAN/wider_pr_info_FAN_hard.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/FAN/wider_pr_info_FAN_hard.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/FAN/wider_pr_info_FAN_medium.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/FAN/wider_pr_info_FAN_medium.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/FANet/wider_pr_info_FANet_easy.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/FANet/wider_pr_info_FANet_easy.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/FANet/wider_pr_info_FANet_hard.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/FANet/wider_pr_info_FANet_hard.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/FANet/wider_pr_info_FANet_medium.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/FANet/wider_pr_info_FANet_medium.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/FDNet/wider_pr_info_FDNet_easy.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/FDNet/wider_pr_info_FDNet_easy.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/FDNet/wider_pr_info_FDNet_hard.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/FDNet/wider_pr_info_FDNet_hard.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/FDNet/wider_pr_info_FDNet_medium.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/FDNet/wider_pr_info_FDNet_medium.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/Face R-CNN/wider_pr_info_Face R-CNN_easy.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/Face R-CNN/wider_pr_info_Face R-CNN_easy.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/Face R-CNN/wider_pr_info_Face R-CNN_hard.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/Face R-CNN/wider_pr_info_Face R-CNN_hard.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/Face R-CNN/wider_pr_info_Face R-CNN_medium.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/Face R-CNN/wider_pr_info_Face R-CNN_medium.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/Face R-FCN/wider_pr_info_Face R-FCN_easy.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/Face R-FCN/wider_pr_info_Face R-FCN_easy.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/Face R-FCN/wider_pr_info_Face R-FCN_hard.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/Face R-FCN/wider_pr_info_Face R-FCN_hard.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/Face R-FCN/wider_pr_info_Face R-FCN_medium.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/Face R-FCN/wider_pr_info_Face R-FCN_medium.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/HR/wider_pr_info_HR_easy.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/HR/wider_pr_info_HR_easy.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/HR/wider_pr_info_HR_hard.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/HR/wider_pr_info_HR_hard.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/HR/wider_pr_info_HR_medium.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/HR/wider_pr_info_HR_medium.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/LDCF+/wider_pr_info_LDCF+_easy.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/LDCF+/wider_pr_info_LDCF+_easy.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/LDCF+/wider_pr_info_LDCF+_hard.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/LDCF+/wider_pr_info_LDCF+_hard.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/LDCF+/wider_pr_info_LDCF+_medium.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/LDCF+/wider_pr_info_LDCF+_medium.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/MSCNN/wider_pr_info_MSCNN_easy.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/MSCNN/wider_pr_info_MSCNN_easy.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/MSCNN/wider_pr_info_MSCNN_hard.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/MSCNN/wider_pr_info_MSCNN_hard.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/MSCNN/wider_pr_info_MSCNN_medium.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/MSCNN/wider_pr_info_MSCNN_medium.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/PyramidBox/wider_pr_info_PyramidBox_easy.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/PyramidBox/wider_pr_info_PyramidBox_easy.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/PyramidBox/wider_pr_info_PyramidBox_hard.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/PyramidBox/wider_pr_info_PyramidBox_hard.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/PyramidBox/wider_pr_info_PyramidBox_medium.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/PyramidBox/wider_pr_info_PyramidBox_medium.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/SFD/wider_pr_info_SFD_easy.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/SFD/wider_pr_info_SFD_easy.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/SFD/wider_pr_info_SFD_hard.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/SFD/wider_pr_info_SFD_hard.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/SFD/wider_pr_info_SFD_medium.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/SFD/wider_pr_info_SFD_medium.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/SRN/wider_pr_info_SRN_easy.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/SRN/wider_pr_info_SRN_easy.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/SRN/wider_pr_info_SRN_hard.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/SRN/wider_pr_info_SRN_hard.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/SRN/wider_pr_info_SRN_medium.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/SRN/wider_pr_info_SRN_medium.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/SSH/wider_pr_info_SSH_easy.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/SSH/wider_pr_info_SSH_easy.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/SSH/wider_pr_info_SSH_hard.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/SSH/wider_pr_info_SSH_hard.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/SSH/wider_pr_info_SSH_medium.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/SSH/wider_pr_info_SSH_medium.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/ScaleFace/wider_pr_info_ScaleFace_easy.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/ScaleFace/wider_pr_info_ScaleFace_easy.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/ScaleFace/wider_pr_info_ScaleFace_hard.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/ScaleFace/wider_pr_info_ScaleFace_hard.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/ScaleFace/wider_pr_info_ScaleFace_medium.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/ScaleFace/wider_pr_info_ScaleFace_medium.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/ZCC/wider_pr_info_ZCC_easy.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/ZCC/wider_pr_info_ZCC_easy.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/ZCC/wider_pr_info_ZCC_hard.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/ZCC/wider_pr_info_ZCC_hard.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/ZCC/wider_pr_info_ZCC_medium.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/ZCC/wider_pr_info_ZCC_medium.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/acf/wider_pr_info_acf_easy.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/acf/wider_pr_info_acf_easy.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/acf/wider_pr_info_acf_hard.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/acf/wider_pr_info_acf_hard.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/acf/wider_pr_info_acf_medium.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/acf/wider_pr_info_acf_medium.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/cms-rcnn/wider_pr_info_cms-rcnn_easy.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/cms-rcnn/wider_pr_info_cms-rcnn_easy.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/cms-rcnn/wider_pr_info_cms-rcnn_hard.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/cms-rcnn/wider_pr_info_cms-rcnn_hard.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/cms-rcnn/wider_pr_info_cms-rcnn_medium.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/cms-rcnn/wider_pr_info_cms-rcnn_medium.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/faceness/wider_pr_info_faceness_easy.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/faceness/wider_pr_info_faceness_easy.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/faceness/wider_pr_info_faceness_hard.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/faceness/wider_pr_info_faceness_hard.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/faceness/wider_pr_info_faceness_medium.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/faceness/wider_pr_info_faceness_medium.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/multiscale_cascade/wider_pr_info_multiscale_cascade_easy.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/multiscale_cascade/wider_pr_info_multiscale_cascade_easy.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/multiscale_cascade/wider_pr_info_multiscale_cascade_hard.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/multiscale_cascade/wider_pr_info_multiscale_cascade_hard.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/multiscale_cascade/wider_pr_info_multiscale_cascade_medium.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/multiscale_cascade/wider_pr_info_multiscale_cascade_medium.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/multitask-cascade-cnn/wider_pr_info_multitask-cascade-cnn_easy.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/multitask-cascade-cnn/wider_pr_info_multitask-cascade-cnn_easy.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/multitask-cascade-cnn/wider_pr_info_multitask-cascade-cnn_hard.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/multitask-cascade-cnn/wider_pr_info_multitask-cascade-cnn_hard.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/multitask-cascade-cnn/wider_pr_info_multitask-cascade-cnn_medium.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/multitask-cascade-cnn/wider_pr_info_multitask-cascade-cnn_medium.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/two_stage_cnn/wider_pr_info_two_stage_cnn_easy.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/two_stage_cnn/wider_pr_info_two_stage_cnn_easy.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/two_stage_cnn/wider_pr_info_two_stage_cnn_hard.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/two_stage_cnn/wider_pr_info_two_stage_cnn_hard.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Test/setting_int/two_stage_cnn/wider_pr_info_two_stage_cnn_medium.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Test/setting_int/two_stage_cnn/wider_pr_info_two_stage_cnn_medium.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/DSFD/wider_pr_info_DSFD_easy_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/DSFD/wider_pr_info_DSFD_easy_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/DSFD/wider_pr_info_DSFD_hard_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/DSFD/wider_pr_info_DSFD_hard_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/DSFD/wider_pr_info_DSFD_medium_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/DSFD/wider_pr_info_DSFD_medium_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/FAN/wider_pr_info_fan_easy_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/FAN/wider_pr_info_fan_easy_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/FAN/wider_pr_info_fan_hard_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/FAN/wider_pr_info_fan_hard_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/FAN/wider_pr_info_fan_medium_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/FAN/wider_pr_info_fan_medium_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/FANet/wider_pr_info_FANet_easy_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/FANet/wider_pr_info_FANet_easy_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/FANet/wider_pr_info_FANet_hard_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/FANet/wider_pr_info_FANet_hard_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/FANet/wider_pr_info_FANet_medium_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/FANet/wider_pr_info_FANet_medium_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/FDNet/wider_pr_info_FDNet_easy_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/FDNet/wider_pr_info_FDNet_easy_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/FDNet/wider_pr_info_FDNet_hard_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/FDNet/wider_pr_info_FDNet_hard_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/FDNet/wider_pr_info_FDNet_medium_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/FDNet/wider_pr_info_FDNet_medium_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/Face R-CNN/wider_pr_info_Face R-CNN_easy_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/Face R-CNN/wider_pr_info_Face R-CNN_easy_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/Face R-CNN/wider_pr_info_Face R-CNN_hard_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/Face R-CNN/wider_pr_info_Face R-CNN_hard_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/Face R-CNN/wider_pr_info_Face R-CNN_medium_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/Face R-CNN/wider_pr_info_Face R-CNN_medium_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/Face R-FCN/wider_pr_info_Face R-FCN_easy_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/Face R-FCN/wider_pr_info_Face R-FCN_easy_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/Face R-FCN/wider_pr_info_Face R-FCN_hard_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/Face R-FCN/wider_pr_info_Face R-FCN_hard_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/Face R-FCN/wider_pr_info_Face R-FCN_medium_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/Face R-FCN/wider_pr_info_Face R-FCN_medium_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/HR/wider_pr_info_HR_easy_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/HR/wider_pr_info_HR_easy_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/HR/wider_pr_info_HR_hard_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/HR/wider_pr_info_HR_hard_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/HR/wider_pr_info_HR_medium_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/HR/wider_pr_info_HR_medium_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/LDCF+/wider_pr_info_LDCF+_easy_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/LDCF+/wider_pr_info_LDCF+_easy_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/LDCF+/wider_pr_info_LDCF+_hard_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/LDCF+/wider_pr_info_LDCF+_hard_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/LDCF+/wider_pr_info_LDCF+_medium_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/LDCF+/wider_pr_info_LDCF+_medium_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/MSCNN/wider_pr_info_MSCNN_easy_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/MSCNN/wider_pr_info_MSCNN_easy_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/MSCNN/wider_pr_info_MSCNN_hard_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/MSCNN/wider_pr_info_MSCNN_hard_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/MSCNN/wider_pr_info_MSCNN_medium_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/MSCNN/wider_pr_info_MSCNN_medium_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/PyramidBox/wider_pr_info_PyramidBox_easy_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/PyramidBox/wider_pr_info_PyramidBox_easy_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/PyramidBox/wider_pr_info_PyramidBox_hard_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/PyramidBox/wider_pr_info_PyramidBox_hard_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/PyramidBox/wider_pr_info_PyramidBox_medium_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/PyramidBox/wider_pr_info_PyramidBox_medium_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/SFD/wider_pr_info_SFD_easy_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/SFD/wider_pr_info_SFD_easy_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/SFD/wider_pr_info_SFD_hard_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/SFD/wider_pr_info_SFD_hard_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/SFD/wider_pr_info_SFD_medium_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/SFD/wider_pr_info_SFD_medium_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/SRN/wider_pr_info_SRN_easy_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/SRN/wider_pr_info_SRN_easy_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/SRN/wider_pr_info_SRN_hard_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/SRN/wider_pr_info_SRN_hard_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/SRN/wider_pr_info_SRN_medium_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/SRN/wider_pr_info_SRN_medium_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/SSH/wider_pr_info_SSH_easy_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/SSH/wider_pr_info_SSH_easy_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/SSH/wider_pr_info_SSH_hard_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/SSH/wider_pr_info_SSH_hard_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/SSH/wider_pr_info_SSH_medium_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/SSH/wider_pr_info_SSH_medium_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/ScaleFace/wider_pr_info_ScaleFace_easy_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/ScaleFace/wider_pr_info_ScaleFace_easy_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/ScaleFace/wider_pr_info_ScaleFace_hard_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/ScaleFace/wider_pr_info_ScaleFace_hard_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/ScaleFace/wider_pr_info_ScaleFace_medium_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/ScaleFace/wider_pr_info_ScaleFace_medium_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/ZCC/wider_pr_info_ZCC_easy_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/ZCC/wider_pr_info_ZCC_easy_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/ZCC/wider_pr_info_ZCC_hard_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/ZCC/wider_pr_info_ZCC_hard_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/ZCC/wider_pr_info_ZCC_medium_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/ZCC/wider_pr_info_ZCC_medium_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/acf/wider_pr_info_acf_easy_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/acf/wider_pr_info_acf_easy_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/acf/wider_pr_info_acf_hard_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/acf/wider_pr_info_acf_hard_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/acf/wider_pr_info_acf_medium_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/acf/wider_pr_info_acf_medium_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/cms-rcnn/wider_pr_info_cms-rcnn_easy_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/cms-rcnn/wider_pr_info_cms-rcnn_easy_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/cms-rcnn/wider_pr_info_cms-rcnn_hard_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/cms-rcnn/wider_pr_info_cms-rcnn_hard_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/cms-rcnn/wider_pr_info_cms-rcnn_medium_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/cms-rcnn/wider_pr_info_cms-rcnn_medium_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/faceness/wider_pr_info_faceness_easy_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/faceness/wider_pr_info_faceness_easy_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/faceness/wider_pr_info_faceness_hard_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/faceness/wider_pr_info_faceness_hard_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/faceness/wider_pr_info_faceness_medium_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/faceness/wider_pr_info_faceness_medium_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/multiscale_cascade/wider_pr_info_multiscale_cascade_easy_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/multiscale_cascade/wider_pr_info_multiscale_cascade_easy_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/multiscale_cascade/wider_pr_info_multiscale_cascade_hard_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/multiscale_cascade/wider_pr_info_multiscale_cascade_hard_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/multiscale_cascade/wider_pr_info_multiscale_cascade_medium_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/multiscale_cascade/wider_pr_info_multiscale_cascade_medium_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/multitask-cascade-cnn/wider_pr_info_multitask-cascade-cnn_easy_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/multitask-cascade-cnn/wider_pr_info_multitask-cascade-cnn_easy_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/multitask-cascade-cnn/wider_pr_info_multitask-cascade-cnn_hard_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/multitask-cascade-cnn/wider_pr_info_multitask-cascade-cnn_hard_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/multitask-cascade-cnn/wider_pr_info_multitask-cascade-cnn_medium_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/multitask-cascade-cnn/wider_pr_info_multitask-cascade-cnn_medium_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/s3fd.pytorch/wider_pr_info_s3fd.pytorch_easy_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/s3fd.pytorch/wider_pr_info_s3fd.pytorch_easy_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/s3fd.pytorch/wider_pr_info_s3fd.pytorch_hard_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/s3fd.pytorch/wider_pr_info_s3fd.pytorch_hard_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/s3fd.pytorch/wider_pr_info_s3fd.pytorch_medium_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/s3fd.pytorch/wider_pr_info_s3fd.pytorch_medium_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/two_stage_cnn/wider_pr_info_two_stage_cnn_easy_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/two_stage_cnn/wider_pr_info_two_stage_cnn_easy_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/two_stage_cnn/wider_pr_info_two_stage_cnn_hard_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/two_stage_cnn/wider_pr_info_two_stage_cnn_hard_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/baselines/Val/setting_int/two_stage_cnn/wider_pr_info_two_stage_cnn_medium_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/baselines/Val/setting_int/two_stage_cnn/wider_pr_info_two_stage_cnn_medium_val.mat -------------------------------------------------------------------------------- /eval_tools/plot/figure/Test/wider_pr_cruve_ext_easy.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/figure/Test/wider_pr_cruve_ext_easy.pdf -------------------------------------------------------------------------------- /eval_tools/plot/figure/Test/wider_pr_cruve_ext_hard.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/figure/Test/wider_pr_cruve_ext_hard.pdf -------------------------------------------------------------------------------- /eval_tools/plot/figure/Test/wider_pr_cruve_ext_medium.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/figure/Test/wider_pr_cruve_ext_medium.pdf -------------------------------------------------------------------------------- /eval_tools/plot/figure/Test/wider_pr_cruve_int_easy.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/figure/Test/wider_pr_cruve_int_easy.pdf -------------------------------------------------------------------------------- /eval_tools/plot/figure/Test/wider_pr_cruve_int_hard.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/figure/Test/wider_pr_cruve_int_hard.pdf -------------------------------------------------------------------------------- /eval_tools/plot/figure/Test/wider_pr_cruve_int_medium.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/figure/Test/wider_pr_cruve_int_medium.pdf -------------------------------------------------------------------------------- /eval_tools/plot/figure/Val/wider_pr_cruve_int_easy_val.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/figure/Val/wider_pr_cruve_int_easy_val.pdf -------------------------------------------------------------------------------- /eval_tools/plot/figure/Val/wider_pr_cruve_int_hard_val.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/figure/Val/wider_pr_cruve_int_hard_val.pdf -------------------------------------------------------------------------------- /eval_tools/plot/figure/Val/wider_pr_cruve_int_medium_val.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/plot/figure/Val/wider_pr_cruve_int_medium_val.pdf -------------------------------------------------------------------------------- /eval_tools/wider_face_test.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/wider_face_test.mat -------------------------------------------------------------------------------- /eval_tools/wider_face_val.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/eval_tools/wider_face_val.mat -------------------------------------------------------------------------------- /img/blackpink.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/img/blackpink.jpg -------------------------------------------------------------------------------- /layers/functions/detection.py: -------------------------------------------------------------------------------- 1 | #-*- coding:utf-8 -*- 2 | 3 | from __future__ import division 4 | from __future__ import absolute_import 5 | from __future__ import print_function 6 | 7 | import torch 8 | 9 | from ..bbox_utils import decode, nms 10 | from torch.autograd import Function 11 | 12 | 13 | class Detect(Function): 14 | """At test time, Detect is the final layer of SSD. Decode location preds, 15 | apply non-maximum suppression to location predictions based on conf 16 | scores and threshold to a top_k number of output predictions for both 17 | confidence score and locations. 18 | """ 19 | 20 | def __init__(self, cfg): 21 | self.num_classes = cfg.NUM_CLASSES 22 | self.top_k = cfg.TOP_K 23 | self.nms_thresh = cfg.NMS_THRESH 24 | self.conf_thresh = cfg.CONF_THRESH 25 | self.variance = cfg.VARIANCE 26 | self.nms_top_k = cfg.NMS_TOP_K 27 | 28 | def forward(self, loc_data, conf_data, prior_data): 29 | """ 30 | Args: 31 | loc_data: (tensor) Loc preds from loc layers 32 | Shape: [batch,num_priors*4] 33 | conf_data: (tensor) Shape: Conf preds from conf layers 34 | Shape: [batch*num_priors,num_classes] 35 | prior_data: (tensor) Prior boxes and variances from priorbox layers 36 | Shape: [1,num_priors,4] 37 | """ 38 | num = loc_data.size(0) 39 | num_priors = prior_data.size(0) 40 | 41 | conf_preds = conf_data.view( 42 | num, num_priors, self.num_classes).transpose(2, 1) 43 | batch_priors = prior_data.view(-1, num_priors, 44 | 4).expand(num, num_priors, 4) 45 | batch_priors = batch_priors.contiguous().view(-1, 4) 46 | 47 | decoded_boxes = decode(loc_data.view(-1, 4), 48 | batch_priors, self.variance) 49 | decoded_boxes = decoded_boxes.view(num, num_priors, 4) 50 | 51 | output = torch.zeros(num, self.num_classes, self.top_k, 5) 52 | 53 | for i in range(num): 54 | boxes = decoded_boxes[i].clone() 55 | conf_scores = conf_preds[i].clone() 56 | 57 | for cl in range(1, self.num_classes): 58 | c_mask = conf_scores[cl].gt(self.conf_thresh) 59 | scores = conf_scores[cl][c_mask] 60 | 61 | if scores.dim() == 0: 62 | continue 63 | l_mask = c_mask.unsqueeze(1).expand_as(boxes) 64 | boxes_ = boxes[l_mask].view(-1, 4) 65 | try: 66 | ids, count = nms( 67 | boxes_, scores, self.nms_thresh, self.nms_top_k) 68 | count = count if count < self.top_k else self.top_k 69 | output[i, cl, :count] = torch.cat((scores[ids[:count]].unsqueeze(1), 70 | boxes_[ids[:count]]), 1) 71 | except: 72 | print('zero') 73 | 74 | return output 75 | -------------------------------------------------------------------------------- /layers/functions/prior_box.py: -------------------------------------------------------------------------------- 1 | #-*- coding:utf-8 -*- 2 | 3 | from __future__ import division 4 | from __future__ import absolute_import 5 | from __future__ import print_function 6 | 7 | import torch 8 | from itertools import product as product 9 | import math 10 | 11 | 12 | class PriorBox(object): 13 | """Compute priorbox coordinates in center-offset form for each source 14 | feature map. 15 | """ 16 | 17 | def __init__(self, input_size, feature_maps,cfg): 18 | super(PriorBox, self).__init__() 19 | self.imh = input_size[0] 20 | self.imw = input_size[1] 21 | 22 | # number of priors for feature map location (either 4 or 6) 23 | self.variance = cfg.VARIANCE or [0.1] 24 | #self.feature_maps = cfg.FEATURE_MAPS 25 | self.min_sizes = cfg.ANCHOR_SIZES 26 | self.steps = cfg.STEPS 27 | self.clip = cfg.CLIP 28 | for v in self.variance: 29 | if v <= 0: 30 | raise ValueError('Variances must be greater than 0') 31 | self.feature_maps = feature_maps 32 | 33 | 34 | def forward(self): 35 | mean = [] 36 | for k in range(len(self.feature_maps)): 37 | feath = self.feature_maps[k][0] 38 | featw = self.feature_maps[k][1] 39 | for i, j in product(range(feath), range(featw)): 40 | f_kw = self.imw / self.steps[k] 41 | f_kh = self.imh / self.steps[k] 42 | 43 | cx = (j + 0.5) / f_kw 44 | cy = (i + 0.5) / f_kh 45 | 46 | s_kw = self.min_sizes[k] / self.imw 47 | s_kh = self.min_sizes[k] / self.imh 48 | 49 | mean += [cx, cy, s_kw, s_kh] 50 | 51 | output = torch.Tensor(mean).view(-1, 4) 52 | if self.clip: 53 | output.clamp_(max=1, min=0) 54 | return output 55 | 56 | 57 | if __name__ == '__main__': 58 | from data.config import cfg 59 | p = PriorBox([640, 640], cfg) 60 | out = p.forward() 61 | print(out.size()) 62 | -------------------------------------------------------------------------------- /layers/modules/l2norm.py: -------------------------------------------------------------------------------- 1 | #-*- coding:utf-8 -*- 2 | 3 | from __future__ import division 4 | from __future__ import absolute_import 5 | from __future__ import print_function 6 | 7 | 8 | import torch 9 | import torch.nn as nn 10 | import torch.nn.init as init 11 | from torch.autograd import Function 12 | from torch.autograd import Variable 13 | 14 | 15 | 16 | class L2Norm(nn.Module): 17 | def __init__(self,n_channels, scale): 18 | super(L2Norm,self).__init__() 19 | self.n_channels = n_channels 20 | self.gamma = scale or None 21 | self.eps = 1e-10 22 | self.weight = nn.Parameter(torch.Tensor(self.n_channels)) 23 | self.reset_parameters() 24 | 25 | def reset_parameters(self): 26 | init.constant(self.weight,self.gamma) 27 | 28 | def forward(self, x): 29 | norm = x.pow(2).sum(dim=1, keepdim=True).sqrt()+self.eps 30 | #x /= norm 31 | x = torch.div(x,norm) 32 | out = self.weight.unsqueeze(0).unsqueeze(2).unsqueeze(3).expand_as(x) * x 33 | return out 34 | 35 | 36 | -------------------------------------------------------------------------------- /layers/modules/multibox_loss.py: -------------------------------------------------------------------------------- 1 | #-*- coding:utf-8 -*- 2 | 3 | from __future__ import division 4 | from __future__ import absolute_import 5 | from __future__ import print_function 6 | 7 | import math 8 | import torch 9 | import torch.nn as nn 10 | import torch.nn.functional as F 11 | from torch.autograd import Variable 12 | 13 | 14 | from ..bbox_utils import match, log_sum_exp, match_ssd 15 | 16 | 17 | class MultiBoxLoss(nn.Module): 18 | """SSD Weighted Loss Function 19 | Compute Targets: 20 | 1) Produce Confidence Target Indices by matching ground truth boxes 21 | with (default) 'priorboxes' that have jaccard index > threshold parameter 22 | (default threshold: 0.5). 23 | 2) Produce localization target by 'encoding' variance into offsets of ground 24 | truth boxes and their matched 'priorboxes'. 25 | 3) Hard negative mining to filter the excessive number of negative examples 26 | that comes with using a large number of default bounding boxes. 27 | (default negative:positive ratio 3:1) 28 | Objective Loss: 29 | L(x,c,l,g) = (Lconf(x, c) + αLloc(x,l,g)) / N 30 | Where, Lconf is the CrossEntropy Loss and Lloc is the SmoothL1 Loss 31 | weighted by α which is set to 1 by cross val. 32 | Args: 33 | c: class confidences, 34 | l: predicted boxes, 35 | g: ground truth boxes 36 | N: number of matched default boxes 37 | See: https://arxiv.org/pdf/1512.02325.pdf for more details. 38 | """ 39 | 40 | def __init__(self, cfg, dataset, use_gpu=True): 41 | super(MultiBoxLoss, self).__init__() 42 | self.use_gpu = use_gpu 43 | self.num_classes = cfg.NUM_CLASSES 44 | self.negpos_ratio = cfg.NEG_POS_RATIOS 45 | self.variance = cfg.VARIANCE 46 | self.dataset = dataset 47 | if dataset == 'face': 48 | self.threshold = cfg.FACE.OVERLAP_THRESH 49 | self.match = match 50 | elif dataset == 'hand': 51 | self.threshold = cfg.HAND.OVERLAP_THRESH 52 | self.match = match_ssd 53 | else: 54 | self.threshold = cfg.HEAD.OVERLAP_THRESH 55 | self.match = match 56 | 57 | def forward(self, predictions, targets): 58 | """Multibox Loss 59 | Args: 60 | predictions (tuple): A tuple containing loc preds, conf preds, 61 | and prior boxes from SSD net. 62 | conf shape: torch.size(batch_size,num_priors,num_classes) 63 | loc shape: torch.size(batch_size,num_priors,4) 64 | priors shape: torch.size(num_priors,4) 65 | 66 | targets (tensor): Ground truth boxes and labels for a batch, 67 | shape: [batch_size,num_objs,5] (last idx is the label). 68 | """ 69 | loc_data, conf_data, priors = predictions 70 | num = loc_data.size(0) 71 | priors = priors[:loc_data.size(1), :] 72 | num_priors = (priors.size(0)) 73 | num_classes = self.num_classes 74 | 75 | # match priors (default boxes) and ground truth boxes 76 | loc_t = torch.Tensor(num, num_priors, 4) 77 | conf_t = torch.LongTensor(num, num_priors) 78 | for idx in range(num): 79 | truths = targets[idx][:, :-1].data 80 | labels = targets[idx][:, -1].data 81 | defaults = priors.data 82 | self.match(self.threshold, truths, defaults, self.variance, labels, 83 | loc_t, conf_t, idx) 84 | if self.use_gpu: 85 | loc_t = loc_t.cuda() 86 | conf_t = conf_t.cuda() 87 | # wrap targets 88 | loc_t = Variable(loc_t, requires_grad=False) 89 | conf_t = Variable(conf_t, requires_grad=False) 90 | 91 | pos = conf_t > 0 92 | num_pos = pos.sum(dim=1, keepdim=True) 93 | # Localization Loss (Smooth L1) 94 | # Shape: [batch,num_priors,4] 95 | pos_idx = pos.unsqueeze(pos.dim()).expand_as(loc_data) 96 | loc_p = loc_data[pos_idx].view(-1, 4) 97 | loc_t = loc_t[pos_idx].view(-1, 4) 98 | loss_l = F.smooth_l1_loss(loc_p, loc_t, size_average=False) 99 | # print(loc_p) 100 | # Compute max conf across batch for hard negative mining 101 | batch_conf = conf_data.view(-1, self.num_classes) 102 | loss_c = log_sum_exp(batch_conf) - \ 103 | batch_conf.gather(1, conf_t.view(-1, 1)) 104 | 105 | # Hard Negative Mining 106 | loss_c[pos.view(-1, 1)] = 0 # filter out pos boxes for now 107 | loss_c = loss_c.view(num, -1) 108 | _, loss_idx = loss_c.sort(1, descending=True) 109 | _, idx_rank = loss_idx.sort(1) 110 | num_pos = pos.long().sum(1, keepdim=True) 111 | num_neg = torch.clamp(self.negpos_ratio * 112 | num_pos, max=pos.size(1) - 1) 113 | neg = idx_rank < num_neg.expand_as(idx_rank) 114 | 115 | # Confidence Loss Including Positive and Negative Examples 116 | pos_idx = pos.unsqueeze(2).expand_as(conf_data) 117 | neg_idx = neg.unsqueeze(2).expand_as(conf_data) 118 | conf_p = conf_data[(pos_idx + neg_idx).gt(0) 119 | ].view(-1, self.num_classes) 120 | targets_weighted = conf_t[(pos + neg).gt(0)] 121 | loss_c = F.cross_entropy(conf_p, targets_weighted, size_average=False) 122 | 123 | # Sum of losses: L(x,c,l,g) = (Lconf(x, c) + αLloc(x,l,g)) / N 124 | N = num_pos.data.sum() if num_pos.data.sum() > 0 else num 125 | loss_l /= N.float() 126 | loss_c /= N.float() 127 | return loss_l, loss_c 128 | -------------------------------------------------------------------------------- /logger.py: -------------------------------------------------------------------------------- 1 | import scipy.misc 2 | import numpy as np 3 | import tensorflow as tf 4 | 5 | from io import BytesIO 6 | 7 | try: 8 | import nsml 9 | USE_NSML=True 10 | except ImportError: 11 | USE_NSML=False 12 | pass 13 | 14 | 15 | class Logger(object): 16 | def __init__(self, log_dir): 17 | """Create a summary writer logging to log_dir.""" 18 | self.writer = tf.summary.FileWriter(log_dir) 19 | self.last = None 20 | 21 | def scalar_summary(self, tag, value, step, scope=None): 22 | """Log a scalar variable.""" 23 | if USE_NSML: 24 | if self.last and self.last['step'] != step: 25 | nsml.report(scope=scope, **self.last) 26 | self.last = None 27 | if self.last is None: 28 | self.last = {'step': step, 'iter': step, 'epoch': 1} 29 | self.last[tag] = value 30 | 31 | else: 32 | summary = tf.Summary(value=[tf.Summary.Value(tag=tag, simple_value=value)]) 33 | self.writer.add_summary(summary, step) 34 | 35 | def image_summary(self, tag, images, step): 36 | """Log a list of images.""" 37 | 38 | img_summaries = [] 39 | for i, img in enumerate(images): 40 | # Write the image to a string 41 | s = BytesIO() 42 | scipy.misc.toimage(img).save(s, format="png") 43 | 44 | # Create an Image object 45 | img_sum = tf.Summary.Image(encoded_image_string=s.getvalue(), 46 | height=img.shape[0], 47 | width=img.shape[1]) 48 | # Create a Summary value 49 | img_summaries.append(tf.Summary.Value(tag='%s/%d' % (tag, i), image=img_sum)) 50 | 51 | # Create and write Summary 52 | summary = tf.Summary(value=img_summaries) 53 | self.writer.add_summary(summary, step) 54 | 55 | def histo_summary(self, tag, values, step, bins=1000): 56 | """Log a histogram of the tensor of values.""" 57 | 58 | # Create a histogram using numpy 59 | counts, bin_edges = np.histogram(values, bins=bins) 60 | 61 | # Fill the fields of the histogram proto 62 | hist = tf.HistogramProto() 63 | hist.min = float(np.min(values)) 64 | hist.max = float(np.max(values)) 65 | hist.num = int(np.prod(values.shape)) 66 | hist.sum = float(np.sum(values)) 67 | hist.sum_squares = float(np.sum(values ** 2)) 68 | 69 | # Drop the start of the first bin 70 | bin_edges = bin_edges[1:] 71 | 72 | # Add bin edges and counts 73 | for edge in bin_edges: 74 | hist.bucket_limit.append(edge) 75 | for c in counts: 76 | hist.bucket.append(c) 77 | 78 | # Create and write Summary 79 | summary = tf.Summary(value=[tf.Summary.Value(tag=tag, histo=hist)]) 80 | self.writer.add_summary(summary, step) 81 | self.writer.flush() 82 | 83 | -------------------------------------------------------------------------------- /logs/tensorboard/empty: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/logs/tensorboard/empty -------------------------------------------------------------------------------- /mobileFacenet_32_PReLU.py: -------------------------------------------------------------------------------- 1 | import torch.nn as nn 2 | import math 3 | import torch 4 | import torch.nn.functional as F 5 | 6 | 7 | def conv_bn(inp, oup, stride, k_size=3): 8 | return nn.Sequential( 9 | nn.Conv2d(inp, oup, k_size, stride, 1, bias=False), 10 | nn.BatchNorm2d(oup), 11 | nn.PReLU() 12 | ) 13 | 14 | 15 | def conv_1x1_bn(inp, oup): 16 | return nn.Sequential( 17 | nn.Conv2d(inp, oup, 1, 1, 0, bias=False), 18 | nn.BatchNorm2d(oup), 19 | nn.PReLU() 20 | ) 21 | 22 | class DWC(nn.Module): 23 | def __init__(self, in_channels, out_channels): 24 | super(DWC, self).__init__() 25 | #self.depthwise = nn.Conv2d(in_channels=in_channels, out_channels=in_channels, kernel_size=(7,6), 26 | #stride=1, padding=0, groups=in_channels, bias=False) 27 | self.batch_norm_in = nn.BatchNorm2d(in_channels) 28 | self.depthwise = nn.AvgPool2d((7, 6), stride=1, padding=0) 29 | self.pointwise = nn.Conv2d(in_channels=in_channels, out_channels=out_channels, kernel_size=1, 30 | stride=1, padding=0, bias=False) 31 | 32 | def forward(self, x): 33 | x = self.depthwise(x) 34 | #x = self.batch_norm_in(x) 35 | x = self.pointwise(x) 36 | return x 37 | 38 | class Max_AvgPool(nn.Module): 39 | def __init__(self, kernel_size=(3,3), stride=2, padding=1, dim=128): 40 | super(Max_AvgPool, self).__init__() 41 | self.Maxpool = nn.MaxPool2d(kernel_size=kernel_size, stride=stride, padding=padding) 42 | self.Avgpool = nn.AvgPool2d(kernel_size=kernel_size, stride=stride, padding=padding) 43 | 44 | def forward(self, x): 45 | x = self.Maxpool(x) + self.Avgpool(x) # add some channelwise gating? 46 | return x 47 | 48 | class Max_AvgPool(nn.Module): 49 | def __init__(self, kernel_size=(3,3), stride=2, padding=1, dim=128): 50 | super(Max_AvgPool, self).__init__() 51 | self.Maxpool = nn.MaxPool2d(kernel_size=kernel_size, stride=stride, padding=padding) 52 | self.Avgpool = nn.AvgPool2d(kernel_size=kernel_size, stride=stride, padding=padding) 53 | 54 | def forward(self, x): 55 | x = self.Maxpool(x) + self.Avgpool(x) # add some channelwise gating? 56 | return x 57 | 58 | class gated_conv1x1(nn.Module): 59 | def __init__(self, inc=128, outc=128): 60 | super(gated_conv1x1, self).__init__() 61 | self.inp = int(inc/2) 62 | self.oup = int(outc/2) 63 | self.conv1x1_1 = nn.Conv2d(self.inp, self.oup, 1, 1, 0, bias=False) 64 | self.gate_1 = nn.Conv2d(self.inp, self.oup, 1, 1, 0, bias=True) 65 | self.conv1x1_2 = nn.Conv2d(self.inp, self.oup, 1, 1, 0, bias=False) 66 | self.gate_2 = nn.Conv2d(self.inp, self.oup, 1, 1, 0, bias=True) 67 | 68 | def forward(self, x): 69 | x_1 = x[:, :self.inp, :, :] 70 | x_2 = x[:, self.inp:, :, :] 71 | 72 | a_1 = self.conv1x1_1(x_1) 73 | g_1 = F.sigmoid(self.gate_1(x_1)) 74 | 75 | a_2 = self.conv1x1_2(x_2) 76 | g_2 = F.sigmoid(self.gate_2(x_2)) 77 | 78 | ret = torch.cat((a_1*g_1, a_2*g_2), 1) 79 | 80 | return ret 81 | 82 | 83 | class InvertedResidual_dwc(nn.Module): 84 | def __init__(self, inp, oup, stride, expand_ratio): 85 | super(InvertedResidual_dwc, self).__init__() 86 | self.stride = stride 87 | assert stride in [1, 2] 88 | 89 | hidden_dim = int(round(inp * expand_ratio)) 90 | self.use_res_connect = self.stride == 1 and inp == oup 91 | 92 | self.conv = [] 93 | 94 | if expand_ratio == 1: 95 | self.conv.append(nn.Conv2d(inp, hidden_dim, kernel_size=(3, 3), stride=stride, padding=1, groups=hidden_dim)) 96 | self.conv.append(nn.BatchNorm2d(hidden_dim)) 97 | self.conv.append(nn.PReLU()) 98 | #self.conv.append(nn.MaxPool2d(kernel_size=(3, 3), stride=stride, padding=1)) 99 | #self.conv.append(gated_conv1x1(inc=hidden_dim,outc=oup)) 100 | self.conv.append(nn.Conv2d(hidden_dim, oup, 1, 1, 0, bias=False)) 101 | self.conv.append(nn.BatchNorm2d(oup)) 102 | self.conv.append(nn.PReLU()) 103 | else: 104 | #self.conv.append(gated_conv1x1(inc=inp,outc=hidden_dim)) 105 | self.conv.append(nn.Conv2d(inp, hidden_dim, 1, 1, 0, bias=False)) 106 | self.conv.append(nn.BatchNorm2d(hidden_dim)) 107 | self.conv.append(nn.PReLU()) 108 | self.conv.append(nn.Conv2d(hidden_dim, hidden_dim, kernel_size=(3, 3), stride=stride, padding=1, groups=hidden_dim)) 109 | self.conv.append(nn.BatchNorm2d(hidden_dim)) 110 | self.conv.append(nn.PReLU()) 111 | #self.conv.append(gated_conv1x1(inc=hidden_dim,outc=oup)) 112 | self.conv.append(nn.Conv2d(hidden_dim, oup, 1, 1, 0, bias=False)) 113 | self.conv.append(nn.BatchNorm2d(oup)) 114 | self.conv.append(nn.PReLU()) 115 | 116 | self.conv = nn.Sequential(*self.conv) 117 | 118 | def forward(self, x): 119 | if self.use_res_connect: 120 | return x + self.conv(x) 121 | else: 122 | return self.conv(x) 123 | 124 | 125 | 126 | class InvertedResidual(nn.Module): 127 | def __init__(self, inp, oup, stride, expand_ratio): 128 | super(InvertedResidual, self).__init__() 129 | self.stride = stride 130 | assert stride in [1, 2] 131 | 132 | hidden_dim = int(round(inp * expand_ratio)) 133 | self.use_res_connect = self.stride == 1 and inp == oup 134 | 135 | self.conv = [] 136 | 137 | if expand_ratio == 1: 138 | 139 | self.conv.append(nn.MaxPool2d(kernel_size=(3, 3), stride=stride, padding=1)) 140 | #self.conv.append(gated_conv1x1(inc=hidden_dim,outc=oup)) 141 | self.conv.append(nn.Conv2d(hidden_dim, oup, 1, 1, 0, bias=False)) 142 | self.conv.append(nn.BatchNorm2d(oup)) 143 | else: 144 | #self.conv.append(gated_conv1x1(inc=inp,outc=hidden_dim)) 145 | self.conv.append(nn.Conv2d(inp, hidden_dim, 1, 1, 0, bias=False)) 146 | self.conv.append(nn.BatchNorm2d(hidden_dim)) 147 | self.conv.append(nn.PReLU()) 148 | self.conv.append(nn.MaxPool2d(kernel_size=(3, 3), stride=stride, padding=1)) 149 | #self.conv.append(gated_conv1x1(inc=hidden_dim,outc=oup)) 150 | self.conv.append(nn.Conv2d(hidden_dim, oup, 1, 1, 0, bias=False)) 151 | self.conv.append(nn.BatchNorm2d(oup)) 152 | 153 | self.conv = nn.Sequential(*self.conv) 154 | 155 | def forward(self, x): 156 | if self.use_res_connect: 157 | return x + self.conv(x) 158 | else: 159 | return self.conv(x) 160 | 161 | 162 | class Net(nn.Module): #mobileNet v2 163 | def __init__(self, embedding_size=128, input_size=224, width_mult=1.): 164 | super(Net, self).__init__() 165 | block = InvertedResidual 166 | block_dwc = InvertedResidual_dwc 167 | input_channel = 64 168 | last_channel = 256 169 | interverted_residual_setting = [ 170 | # t, c, n, s 171 | [1, 32, 1, 1], # depthwise conv for first row 172 | [2, 32, 2, 1], 173 | [4, 32, 2, 1], 174 | [2, 32, 2, 2], 175 | [4, 32, 5, 1], 176 | [2, 32, 2, 2], 177 | [2, 32, 6, 2], 178 | ] 179 | 180 | # building first layer 181 | input_channel = int(input_channel * width_mult) 182 | self.last_channel = int(last_channel * width_mult) if width_mult > 1.0 else last_channel 183 | self.features = [conv_bn(3, input_channel, 2)] 184 | 185 | # building inverted residual 186 | cnt = 0 187 | for t, c, n, s in interverted_residual_setting: 188 | output_channel = int(c * width_mult) 189 | for i in range(n): 190 | if cnt>1: 191 | if i == n - 1: # reduce the featuremap in the last. 192 | self.features.append(block_dwc(input_channel, output_channel, s, expand_ratio=t)) 193 | else: 194 | self.features.append(block_dwc(input_channel, output_channel, 1, expand_ratio=t)) 195 | input_channel = output_channel 196 | else: 197 | if i == n - 1: # reduce the featuremap in the last. 198 | self.features.append(block_dwc(input_channel, output_channel, s, expand_ratio=t)) 199 | else: 200 | self.features.append(block_dwc(input_channel, output_channel, 1, expand_ratio=t)) 201 | input_channel = output_channel 202 | 203 | cnt+=1 204 | 205 | # building last several layers 206 | self.features.append(gated_conv1x1(input_channel, self.last_channel)) 207 | 208 | # make it nn.Sequential 209 | self.features_sequential = nn.Sequential(*self.features) 210 | 211 | # Global depthwise conv 212 | #self.GDCconv = DWC(self.last_channel, embedding_size) 213 | 214 | 215 | self._initialize_weights() 216 | 217 | def forward(self, x): 218 | x = self.features_sequential(x).view(-1, 256*4) 219 | 220 | return x 221 | 222 | def _initialize_weights(self): 223 | for m in self.modules(): 224 | if isinstance(m, nn.Conv2d): 225 | n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels 226 | m.weight.data.normal_(0, math.sqrt(2. / n)) 227 | if m.bias is not None: 228 | m.bias.data.zero_() 229 | elif isinstance(m, nn.BatchNorm2d): 230 | m.weight.data.fill_(1) 231 | m.bias.data.zero_() 232 | elif isinstance(m, nn.Linear): 233 | n = m.weight.size(1) 234 | m.weight.data.normal_(0, 0.01) 235 | m.bias.data.zero_() -------------------------------------------------------------------------------- /mobileFacenet_48_PReLU.py: -------------------------------------------------------------------------------- 1 | import torch.nn as nn 2 | import math 3 | import torch 4 | import torch.nn.functional as F 5 | 6 | 7 | def conv_bn(inp, oup, stride, k_size=3): 8 | return nn.Sequential( 9 | nn.Conv2d(inp, oup, k_size, stride, 1, bias=False), 10 | nn.BatchNorm2d(oup), 11 | nn.PReLU() 12 | ) 13 | 14 | 15 | def conv_1x1_bn(inp, oup): 16 | return nn.Sequential( 17 | nn.Conv2d(inp, oup, 1, 1, 0, bias=False), 18 | nn.BatchNorm2d(oup), 19 | nn.PReLU() 20 | ) 21 | 22 | class DWC(nn.Module): 23 | def __init__(self, in_channels, out_channels): 24 | super(DWC, self).__init__() 25 | #self.depthwise = nn.Conv2d(in_channels=in_channels, out_channels=in_channels, kernel_size=(7,6), 26 | #stride=1, padding=0, groups=in_channels, bias=False) 27 | self.batch_norm_in = nn.BatchNorm2d(in_channels) 28 | self.depthwise = nn.AvgPool2d((7, 6), stride=1, padding=0) 29 | self.pointwise = nn.Conv2d(in_channels=in_channels, out_channels=out_channels, kernel_size=1, 30 | stride=1, padding=0, bias=False) 31 | 32 | def forward(self, x): 33 | x = self.depthwise(x) 34 | #x = self.batch_norm_in(x) 35 | x = self.pointwise(x) 36 | return x 37 | 38 | class Max_AvgPool(nn.Module): 39 | def __init__(self, kernel_size=(3,3), stride=2, padding=1, dim=128): 40 | super(Max_AvgPool, self).__init__() 41 | self.Maxpool = nn.MaxPool2d(kernel_size=kernel_size, stride=stride, padding=padding) 42 | self.Avgpool = nn.AvgPool2d(kernel_size=kernel_size, stride=stride, padding=padding) 43 | 44 | def forward(self, x): 45 | x = self.Maxpool(x) + self.Avgpool(x) # add some channelwise gating? 46 | return x 47 | 48 | class Max_AvgPool(nn.Module): 49 | def __init__(self, kernel_size=(3,3), stride=2, padding=1, dim=128): 50 | super(Max_AvgPool, self).__init__() 51 | self.Maxpool = nn.MaxPool2d(kernel_size=kernel_size, stride=stride, padding=padding) 52 | self.Avgpool = nn.AvgPool2d(kernel_size=kernel_size, stride=stride, padding=padding) 53 | 54 | def forward(self, x): 55 | x = self.Maxpool(x) + self.Avgpool(x) # add some channelwise gating? 56 | return x 57 | 58 | class gated_conv1x1(nn.Module): 59 | def __init__(self, inc=128, outc=128): 60 | super(gated_conv1x1, self).__init__() 61 | self.inp = int(inc/2) 62 | self.oup = int(outc/2) 63 | self.conv1x1_1 = nn.Conv2d(self.inp, self.oup, 1, 1, 0, bias=False) 64 | self.gate_1 = nn.Conv2d(self.inp, self.oup, 1, 1, 0, bias=True) 65 | self.conv1x1_2 = nn.Conv2d(self.inp, self.oup, 1, 1, 0, bias=False) 66 | self.gate_2 = nn.Conv2d(self.inp, self.oup, 1, 1, 0, bias=True) 67 | 68 | def forward(self, x): 69 | x_1 = x[:, :self.inp, :, :] 70 | x_2 = x[:, self.inp:, :, :] 71 | 72 | a_1 = self.conv1x1_1(x_1) 73 | g_1 = F.sigmoid(self.gate_1(x_1)) 74 | 75 | a_2 = self.conv1x1_2(x_2) 76 | g_2 = F.sigmoid(self.gate_2(x_2)) 77 | 78 | ret = torch.cat((a_1*g_1, a_2*g_2), 1) 79 | 80 | return ret 81 | 82 | 83 | class InvertedResidual_dwc(nn.Module): 84 | def __init__(self, inp, oup, stride, expand_ratio): 85 | super(InvertedResidual_dwc, self).__init__() 86 | self.stride = stride 87 | assert stride in [1, 2] 88 | 89 | hidden_dim = int(round(inp * expand_ratio)) 90 | self.use_res_connect = self.stride == 1 and inp == oup 91 | 92 | self.conv = [] 93 | 94 | if expand_ratio == 1: 95 | 96 | self.conv.append(nn.Conv2d(inp, hidden_dim, kernel_size=(3, 3), stride=stride, padding=1, groups=hidden_dim)) 97 | self.conv.append(nn.BatchNorm2d(hidden_dim)) 98 | self.conv.append(nn.PReLU()) 99 | #self.conv.append(nn.MaxPool2d(kernel_size=(3, 3), stride=stride, padding=1)) 100 | #self.conv.append(gated_conv1x1(inc=hidden_dim,outc=oup)) 101 | self.conv.append(nn.Conv2d(hidden_dim, oup, 1, 1, 0, bias=False)) 102 | self.conv.append(nn.BatchNorm2d(oup)) 103 | else: 104 | #self.conv.append(gated_conv1x1(inc=inp,outc=hidden_dim)) 105 | self.conv.append(nn.Conv2d(inp, hidden_dim, 1, 1, 0, bias=False)) 106 | self.conv.append(nn.BatchNorm2d(hidden_dim)) 107 | self.conv.append(nn.PReLU()) 108 | self.conv.append(nn.Conv2d(hidden_dim, hidden_dim, kernel_size=(3, 3), stride=stride, padding=1, groups=hidden_dim)) 109 | self.conv.append(nn.BatchNorm2d(hidden_dim)) 110 | self.conv.append(nn.PReLU()) 111 | #self.conv.append(gated_conv1x1(inc=hidden_dim,outc=oup)) 112 | self.conv.append(nn.Conv2d(hidden_dim, oup, 1, 1, 0, bias=False)) 113 | self.conv.append(nn.BatchNorm2d(oup)) 114 | 115 | self.conv = nn.Sequential(*self.conv) 116 | 117 | def forward(self, x): 118 | if self.use_res_connect: 119 | return x + self.conv(x) 120 | else: 121 | return self.conv(x) 122 | 123 | 124 | 125 | class InvertedResidual(nn.Module): 126 | def __init__(self, inp, oup, stride, expand_ratio): 127 | super(InvertedResidual, self).__init__() 128 | self.stride = stride 129 | assert stride in [1, 2] 130 | 131 | hidden_dim = int(round(inp * expand_ratio)) 132 | self.use_res_connect = self.stride == 1 and inp == oup 133 | 134 | self.conv = [] 135 | 136 | if expand_ratio == 1: 137 | 138 | self.conv.append(nn.MaxPool2d(kernel_size=(3, 3), stride=stride, padding=1)) 139 | #self.conv.append(gated_conv1x1(inc=hidden_dim,outc=oup)) 140 | self.conv.append(nn.Conv2d(hidden_dim, oup, 1, 1, 0, bias=False)) 141 | self.conv.append(nn.BatchNorm2d(oup)) 142 | else: 143 | #self.conv.append(gated_conv1x1(inc=inp,outc=hidden_dim)) 144 | self.conv.append(nn.Conv2d(inp, hidden_dim, 1, 1, 0, bias=False)) 145 | self.conv.append(nn.BatchNorm2d(hidden_dim)) 146 | self.conv.append(nn.PReLU()) 147 | self.conv.append(nn.MaxPool2d(kernel_size=(3, 3), stride=stride, padding=1)) 148 | #self.conv.append(gated_conv1x1(inc=hidden_dim,outc=oup)) 149 | self.conv.append(nn.Conv2d(hidden_dim, oup, 1, 1, 0, bias=False)) 150 | self.conv.append(nn.BatchNorm2d(oup)) 151 | 152 | self.conv = nn.Sequential(*self.conv) 153 | 154 | def forward(self, x): 155 | if self.use_res_connect: 156 | return x + self.conv(x) 157 | else: 158 | return self.conv(x) 159 | 160 | 161 | class Net(nn.Module): #mobileNet v2 162 | def __init__(self, embedding_size=128, input_size=224, width_mult=1.): 163 | super(Net, self).__init__() 164 | block = InvertedResidual 165 | block_dwc = InvertedResidual_dwc 166 | input_channel = 64 167 | last_channel = 256 168 | interverted_residual_setting = [ 169 | # t, c, n, s 170 | [1, 48, 1, 1], # depthwise conv for first row 171 | [2, 48, 2, 1], 172 | [4, 48, 2, 2], 173 | [2, 48, 2, 1], 174 | [4, 48, 5, 1], 175 | [2, 48, 2, 2], 176 | [2, 48, 6, 2], 177 | ] 178 | 179 | # building first layer 180 | input_channel = int(input_channel * width_mult) 181 | self.last_channel = int(last_channel * width_mult) if width_mult > 1.0 else last_channel 182 | self.features = [conv_bn(3, input_channel, 2)] 183 | 184 | # building inverted residual 185 | cnt = 0 186 | for t, c, n, s in interverted_residual_setting: 187 | output_channel = int(c * width_mult) 188 | for i in range(n): 189 | if cnt>1: 190 | if i == n - 1: # reduce the featuremap in the last. 191 | self.features.append(block_dwc(input_channel, output_channel, s, expand_ratio=t)) 192 | else: 193 | self.features.append(block_dwc(input_channel, output_channel, 1, expand_ratio=t)) 194 | input_channel = output_channel 195 | else: 196 | if i == n - 1: # reduce the featuremap in the last. 197 | self.features.append(block_dwc(input_channel, output_channel, s, expand_ratio=t)) 198 | else: 199 | self.features.append(block_dwc(input_channel, output_channel, 1, expand_ratio=t)) 200 | input_channel = output_channel 201 | 202 | cnt+=1 203 | 204 | # building last several layers 205 | self.features.append(gated_conv1x1(input_channel, self.last_channel)) 206 | 207 | # make it nn.Sequential 208 | self.features_sequential = nn.Sequential(*self.features) 209 | 210 | # Global depthwise conv 211 | #self.GDCconv = DWC(self.last_channel, embedding_size) 212 | 213 | 214 | self._initialize_weights() 215 | 216 | def forward(self, x): 217 | x = self.features_sequential(x).view(-1, 256*4) 218 | 219 | return x 220 | 221 | def _initialize_weights(self): 222 | for m in self.modules(): 223 | if isinstance(m, nn.Conv2d): 224 | n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels 225 | m.weight.data.normal_(0, math.sqrt(2. / n)) 226 | if m.bias is not None: 227 | m.bias.data.zero_() 228 | elif isinstance(m, nn.BatchNorm2d): 229 | m.weight.data.fill_(1) 230 | m.bias.data.zero_() 231 | elif isinstance(m, nn.Linear): 232 | n = m.weight.size(1) 233 | m.weight.data.normal_(0, 0.01) 234 | m.bias.data.zero_() -------------------------------------------------------------------------------- /mobileFacenet_64_PReLU.py: -------------------------------------------------------------------------------- 1 | import torch.nn as nn 2 | import math 3 | import torch 4 | import torch.nn.functional as F 5 | 6 | 7 | def conv_bn(inp, oup, stride, k_size=3): 8 | return nn.Sequential( 9 | nn.Conv2d(inp, oup, k_size, stride, 1, bias=False), 10 | nn.BatchNorm2d(oup), 11 | nn.PReLU() 12 | 13 | ) 14 | 15 | 16 | def conv_1x1_bn(inp, oup): 17 | return nn.Sequential( 18 | nn.Conv2d(inp, oup, 1, 1, 0, bias=False), 19 | nn.BatchNorm2d(oup), 20 | nn.PReLU() 21 | ) 22 | 23 | class DWC(nn.Module): 24 | def __init__(self, in_channels, out_channels): 25 | super(DWC, self).__init__() 26 | #self.depthwise = nn.Conv2d(in_channels=in_channels, out_channels=in_channels, kernel_size=(7,6), 27 | #stride=1, padding=0, groups=in_channels, bias=False) 28 | self.batch_norm_in = nn.BatchNorm2d(in_channels) 29 | self.depthwise = nn.AvgPool2d((7, 6), stride=1, padding=0) 30 | self.pointwise = nn.Conv2d(in_channels=in_channels, out_channels=out_channels, kernel_size=1, 31 | stride=1, padding=0, bias=False) 32 | 33 | def forward(self, x): 34 | x = self.depthwise(x) 35 | #x = self.batch_norm_in(x) 36 | x = self.pointwise(x) 37 | return x 38 | 39 | class Max_AvgPool(nn.Module): 40 | def __init__(self, kernel_size=(3,3), stride=2, padding=1, dim=128): 41 | super(Max_AvgPool, self).__init__() 42 | self.Maxpool = nn.MaxPool2d(kernel_size=kernel_size, stride=stride, padding=padding) 43 | self.Avgpool = nn.AvgPool2d(kernel_size=kernel_size, stride=stride, padding=padding) 44 | 45 | def forward(self, x): 46 | x = self.Maxpool(x) + self.Avgpool(x) # add some channelwise gating? 47 | return x 48 | 49 | class Max_AvgPool(nn.Module): 50 | def __init__(self, kernel_size=(3,3), stride=2, padding=1, dim=128): 51 | super(Max_AvgPool, self).__init__() 52 | self.Maxpool = nn.MaxPool2d(kernel_size=kernel_size, stride=stride, padding=padding) 53 | self.Avgpool = nn.AvgPool2d(kernel_size=kernel_size, stride=stride, padding=padding) 54 | 55 | def forward(self, x): 56 | x = self.Maxpool(x) + self.Avgpool(x) # add some channelwise gating? 57 | return x 58 | 59 | class gated_conv1x1(nn.Module): 60 | def __init__(self, inc=128, outc=128): 61 | super(gated_conv1x1, self).__init__() 62 | self.inp = int(inc/2) 63 | self.oup = int(outc/2) 64 | self.conv1x1_1 = nn.Conv2d(self.inp, self.oup, 1, 1, 0, bias=False) 65 | self.gate_1 = nn.Conv2d(self.inp, self.oup, 1, 1, 0, bias=True) 66 | self.conv1x1_2 = nn.Conv2d(self.inp, self.oup, 1, 1, 0, bias=False) 67 | self.gate_2 = nn.Conv2d(self.inp, self.oup, 1, 1, 0, bias=True) 68 | 69 | def forward(self, x): 70 | x_1 = x[:, :self.inp, :, :] 71 | x_2 = x[:, self.inp:, :, :] 72 | 73 | a_1 = self.conv1x1_1(x_1) 74 | g_1 = F.sigmoid(self.gate_1(x_1)) 75 | 76 | a_2 = self.conv1x1_2(x_2) 77 | g_2 = F.sigmoid(self.gate_2(x_2)) 78 | 79 | ret = torch.cat((a_1*g_1, a_2*g_2), 1) 80 | 81 | return ret 82 | 83 | 84 | class InvertedResidual_dwc(nn.Module): 85 | def __init__(self, inp, oup, stride, expand_ratio): 86 | super(InvertedResidual_dwc, self).__init__() 87 | self.stride = stride 88 | assert stride in [1, 2] 89 | 90 | hidden_dim = int(round(inp * expand_ratio)) 91 | self.use_res_connect = self.stride == 1 and inp == oup 92 | 93 | self.conv = [] 94 | 95 | if expand_ratio == 1: 96 | 97 | self.conv.append(nn.Conv2d(inp, hidden_dim, kernel_size=(3, 3), stride=stride, padding=1, groups=hidden_dim)) 98 | self.conv.append(nn.BatchNorm2d(hidden_dim)) 99 | self.conv.append(nn.PReLU()) 100 | #self.conv.append(nn.MaxPool2d(kernel_size=(3, 3), stride=stride, padding=1)) 101 | #self.conv.append(gated_conv1x1(inc=hidden_dim,outc=oup)) 102 | self.conv.append(nn.Conv2d(hidden_dim, oup, 1, 1, 0, bias=False)) 103 | self.conv.append(nn.BatchNorm2d(oup)) 104 | else: 105 | #self.conv.append(gated_conv1x1(inc=inp,outc=hidden_dim)) 106 | self.conv.append(nn.Conv2d(inp, hidden_dim, 1, 1, 0, bias=False)) 107 | self.conv.append(nn.BatchNorm2d(hidden_dim)) 108 | self.conv.append(nn.PReLU()) 109 | self.conv.append(nn.Conv2d(hidden_dim, hidden_dim, kernel_size=(3, 3), stride=stride, padding=1, groups=hidden_dim)) 110 | self.conv.append(nn.BatchNorm2d(hidden_dim)) 111 | self.conv.append(nn.PReLU()) 112 | #self.conv.append(gated_conv1x1(inc=hidden_dim,outc=oup)) 113 | self.conv.append(nn.Conv2d(hidden_dim, oup, 1, 1, 0, bias=False)) 114 | self.conv.append(nn.BatchNorm2d(oup)) 115 | 116 | self.conv = nn.Sequential(*self.conv) 117 | 118 | def forward(self, x): 119 | if self.use_res_connect: 120 | return x + self.conv(x) 121 | else: 122 | return self.conv(x) 123 | 124 | 125 | 126 | class InvertedResidual(nn.Module): 127 | def __init__(self, inp, oup, stride, expand_ratio): 128 | super(InvertedResidual, self).__init__() 129 | self.stride = stride 130 | assert stride in [1, 2] 131 | 132 | hidden_dim = int(round(inp * expand_ratio)) 133 | self.use_res_connect = self.stride == 1 and inp == oup 134 | 135 | self.conv = [] 136 | 137 | if expand_ratio == 1: 138 | 139 | self.conv.append(nn.MaxPool2d(kernel_size=(3, 3), stride=stride, padding=1)) 140 | #self.conv.append(gated_conv1x1(inc=hidden_dim,outc=oup)) 141 | self.conv.append(nn.Conv2d(hidden_dim, oup, 1, 1, 0, bias=False)) 142 | self.conv.append(nn.BatchNorm2d(oup)) 143 | else: 144 | #self.conv.append(gated_conv1x1(inc=inp,outc=hidden_dim)) 145 | self.conv.append(nn.Conv2d(inp, hidden_dim, 1, 1, 0, bias=False)) 146 | self.conv.append(nn.BatchNorm2d(hidden_dim)) 147 | self.conv.append(nn.PReLU()) 148 | self.conv.append(nn.MaxPool2d(kernel_size=(3, 3), stride=stride, padding=1)) 149 | #self.conv.append(gated_conv1x1(inc=hidden_dim,outc=oup)) 150 | self.conv.append(nn.Conv2d(hidden_dim, oup, 1, 1, 0, bias=False)) 151 | self.conv.append(nn.BatchNorm2d(oup)) 152 | 153 | self.conv = nn.Sequential(*self.conv) 154 | 155 | def forward(self, x): 156 | if self.use_res_connect: 157 | return x + self.conv(x) 158 | else: 159 | return self.conv(x) 160 | 161 | 162 | class Net(nn.Module): #mobileNet v2 163 | def __init__(self, embedding_size=128, input_size=224, width_mult=1.): 164 | super(Net, self).__init__() 165 | block = InvertedResidual 166 | block_dwc = InvertedResidual_dwc 167 | input_channel = 64 168 | last_channel = 256 169 | interverted_residual_setting = [ 170 | # t, c, n, s 171 | [1, 64, 1, 1], # depthwise conv for first row 172 | [2, 64, 2, 1], 173 | [4, 64, 2, 2], 174 | [2, 64, 2, 1], 175 | [4, 64, 5, 1], 176 | [2, 64, 2, 2], 177 | [2, 64, 6, 2], 178 | ] 179 | 180 | # building first layer 181 | input_channel = int(input_channel * width_mult) 182 | self.last_channel = int(last_channel * width_mult) if width_mult > 1.0 else last_channel 183 | self.features = [conv_bn(3, input_channel, 2)] 184 | 185 | # building inverted residual 186 | cnt = 0 187 | for t, c, n, s in interverted_residual_setting: 188 | output_channel = int(c * width_mult) 189 | for i in range(n): 190 | if cnt>1: 191 | if i == n - 1: # reduce the featuremap in the last. 192 | self.features.append(block_dwc(input_channel, output_channel, s, expand_ratio=t)) 193 | else: 194 | self.features.append(block_dwc(input_channel, output_channel, 1, expand_ratio=t)) 195 | input_channel = output_channel 196 | else: 197 | if i == n - 1: # reduce the featuremap in the last. 198 | self.features.append(block_dwc(input_channel, output_channel, s, expand_ratio=t)) 199 | else: 200 | self.features.append(block_dwc(input_channel, output_channel, 1, expand_ratio=t)) 201 | input_channel = output_channel 202 | 203 | cnt+=1 204 | 205 | # building last several layers 206 | self.features.append(gated_conv1x1(input_channel, self.last_channel)) 207 | 208 | # make it nn.Sequential 209 | self.features_sequential = nn.Sequential(*self.features) 210 | 211 | # Global depthwise conv 212 | #self.GDCconv = DWC(self.last_channel, embedding_size) 213 | 214 | 215 | self._initialize_weights() 216 | 217 | def forward(self, x): 218 | x = self.features_sequential(x).view(-1, 256*4) 219 | 220 | return x 221 | 222 | def _initialize_weights(self): 223 | for m in self.modules(): 224 | if isinstance(m, nn.Conv2d): 225 | n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels 226 | m.weight.data.normal_(0, math.sqrt(2. / n)) 227 | if m.bias is not None: 228 | m.bias.data.zero_() 229 | elif isinstance(m, nn.BatchNorm2d): 230 | m.weight.data.fill_(1) 231 | m.bias.data.zero_() 232 | elif isinstance(m, nn.Linear): 233 | n = m.weight.size(1) 234 | m.weight.data.normal_(0, 0.01) 235 | m.bias.data.zero_() -------------------------------------------------------------------------------- /prepare_hand_dataset.py: -------------------------------------------------------------------------------- 1 | #-*-coding:utf-8 -*- 2 | 3 | from __future__ import print_function 4 | from __future__ import division 5 | from __future__ import absolute_import 6 | 7 | import os 8 | import numpy as np 9 | import csv 10 | 11 | from data.config import cfg 12 | 13 | if not os.path.exists('./data'): 14 | os.makedirs('./data') 15 | 16 | TRAIN_ROOT = os.path.join(cfg.HAND.DIR, 'images', 'train') 17 | TEST_ROOT = os.path.join(cfg.HAND.DIR, 'images', 'test') 18 | 19 | 20 | def generate_file(csv_file, target_file, root): 21 | filenames = [] 22 | bboxes = [] 23 | with open(csv_file, 'rb') as sd: 24 | lines = csv.DictReader(sd) 25 | for line in lines: 26 | filenames.append(os.path.join(root, line['filename'])) 27 | bbox = [int(line['xmin']), int(line['ymin']), 28 | int(line['xmax']), int(line['ymax'])] 29 | bboxes.append(bbox) 30 | 31 | filenames = np.array(filenames) 32 | bboxes = np.array(bboxes) 33 | uniq_filenames = np.unique(filenames) 34 | 35 | fout = open(target_file, 'w') 36 | 37 | for name in uniq_filenames: 38 | idx = np.where(filenames == name)[0] 39 | bbox = bboxes[idx] 40 | fout.write('{} '.format(name)) 41 | fout.write(('{} ').format(len(bbox))) 42 | for loc in bbox: 43 | x1, y1, x2, y2 = loc 44 | fout.write('{} {} {} {} '.format(x1, y1, x2, y2)) 45 | fout.write('\n') 46 | fout.close() 47 | 48 | 49 | if __name__ == '__main__': 50 | train_csv_file = os.path.join(TRAIN_ROOT, 'train_labels.csv') 51 | test_csv_file = os.path.join(TEST_ROOT, 'test_labels.csv') 52 | generate_file(train_csv_file, cfg.HAND.TRAIN_FILE, TRAIN_ROOT) 53 | generate_file(test_csv_file, cfg.HAND.VAL_FILE, TEST_ROOT) 54 | -------------------------------------------------------------------------------- /prepare_wider_data.py: -------------------------------------------------------------------------------- 1 | #-*- coding:utf-8 -*- 2 | 3 | from __future__ import division 4 | from __future__ import absolute_import 5 | from __future__ import print_function 6 | 7 | import os 8 | from data.config import cfg 9 | import cv2 10 | 11 | try: 12 | from nsml import HAS_DATASET, DATASET_PATH, DATASET_NAME 13 | WIDER_ROOT = os.path.join(DATASET_PATH, 'train') 14 | except ImportError: 15 | HAS_DATASET=False 16 | DATASET_PATH=None 17 | DATASET_NAME=None 18 | WIDER_ROOT = '/media/yoo/Data/wider_face' 19 | 20 | 21 | 22 | train_list_file = os.path.join(WIDER_ROOT, 'wider_face_split', 23 | 'wider_face_train_bbx_gt.txt') 24 | val_list_file = os.path.join(WIDER_ROOT, 'wider_face_split', 25 | 'wider_face_val_bbx_gt.txt') 26 | 27 | WIDER_TRAIN = os.path.join(WIDER_ROOT, 'WIDER_train', 'images') 28 | WIDER_VAL = os.path.join(WIDER_ROOT, 'WIDER_val', 'images') 29 | 30 | 31 | def parse_wider_file(root, file): 32 | with open(file, 'r') as fr: 33 | lines = fr.readlines() 34 | face_count = [] 35 | img_paths = [] 36 | face_loc = [] 37 | img_faces = [] 38 | count = 0 39 | flag = False 40 | for k, line in enumerate(lines): 41 | line = line.strip().strip('\n') 42 | if count > 0: 43 | line = line.split(' ') 44 | count -= 1 45 | loc = [int(line[0]), int(line[1]), int(line[2]), int(line[3])] 46 | face_loc += [loc] 47 | if flag: 48 | face_count += [int(line)] 49 | flag = False 50 | count = int(line) 51 | if 'jpg' in line: 52 | img_paths += [os.path.join(root, line)] 53 | flag = True 54 | 55 | total_face = 0 56 | for k in face_count: 57 | face_ = [] 58 | for x in range(total_face, total_face + k): 59 | face_.append(face_loc[x]) 60 | img_faces += [face_] 61 | total_face += k 62 | return img_paths, img_faces 63 | 64 | 65 | def wider_data_file(): 66 | img_paths, bbox = parse_wider_file(WIDER_TRAIN, train_list_file) 67 | fw = open(cfg.FACE.TRAIN_FILE, 'w') 68 | for index in range(len(img_paths)): 69 | path = img_paths[index] 70 | boxes = bbox[index] 71 | fw.write(path) 72 | fw.write(' {}'.format(len(boxes))) 73 | for box in boxes: 74 | data = ' {} {} {} {} {}'.format(box[0], box[1], box[2], box[3], 1) 75 | fw.write(data) 76 | fw.write('\n') 77 | fw.close() 78 | 79 | img_paths, bbox = parse_wider_file(WIDER_VAL, val_list_file) 80 | fw = open(cfg.FACE.VAL_FILE, 'w') 81 | for index in range(len(img_paths)): 82 | path = img_paths[index] 83 | boxes = bbox[index] 84 | fw.write(path) 85 | fw.write(' {}'.format(len(boxes))) 86 | for box in boxes: 87 | data = ' {} {} {} {} {}'.format(box[0], box[1], box[2], box[3], 1) 88 | fw.write(data) 89 | fw.write('\n') 90 | fw.close() 91 | 92 | 93 | if __name__ == '__main__': 94 | wider_data_file() 95 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #nsml: anibali/pytorch:cuda-9.0 2 | # Setup file for pytorch 4.* 3 | from distutils.core import setup 4 | 5 | setup(name='', version='0.1', install_requires=['numpy', 6 | 'pillow', 7 | 'torchvision', 8 | 'tensorboard', 9 | 'matplotlib', 10 | 'tensorboard-logger', 11 | 'tqdm', 12 | 'sklearn', 13 | 'tensorflow', 14 | 'easydict', 15 | 'cython']) 16 | -------------------------------------------------------------------------------- /tmp/blackpink.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/tmp/blackpink.jpg -------------------------------------------------------------------------------- /tools/afw_img_list.txt: -------------------------------------------------------------------------------- 1 | 1004109301 2 | 111076519 3 | 1139324862 4 | 1204062305 5 | 1224897301 6 | 1254885428 7 | 1295311477 8 | 1361196352 9 | 1372188757 10 | 14424972 11 | 156474078 12 | 1587030290 13 | 1634816 14 | 1636651575 15 | 1648807314 16 | 170817766 17 | 1709378501 18 | 174692320 19 | 1814664578 20 | 18489332 21 | 199759840 22 | 2030653815 23 | 2043831280 24 | 2118625994 25 | 2120936774 26 | 213654866 27 | 2147052512 28 | 2186255795 29 | 2233672250 30 | 2239710476 31 | 225191079 32 | 2266416332 33 | 22699817 34 | 2288136183 35 | 2312639559 36 | 2353849 37 | 2372995574 38 | 237815567 39 | 2404040793 40 | 2417212918 41 | 2437602091 42 | 2451065225 43 | 250277765 44 | 2542662563 45 | 2580479214 46 | 261068 47 | 2653111362 48 | 270814102 49 | 2715171150 50 | 281972218 51 | 2844520516 52 | 2863107962 53 | 2911658494 54 | 2939015820 55 | 3062021448 56 | 3089202157 57 | 310076750 58 | 3187108438 59 | 3210734866 60 | 3284354538 61 | 3331716292 62 | 342149506 63 | 3464901851 64 | 346731834 65 | 347629355 66 | 347826333 67 | 3576294411 68 | 364259537 69 | 3662810723 70 | 3684472818 71 | 368987306 72 | 37096733 73 | 3729198156 74 | 3796238727 75 | 3854178896 76 | 3858593140 77 | 3873491482 78 | 3893740955 79 | 3929640120 80 | 3944399031 81 | 3989161 82 | 399829006 83 | 40014967 84 | 4017305068 85 | 4022732812 86 | 406798473 87 | 4082680322 88 | 4141887018 89 | 4174638819 90 | 4237203680 91 | 4250120238 92 | 4253907822 93 | 4285163979 94 | 432269399 95 | 4332978153 96 | 4337161543 97 | 4351876664 98 | 435926861 99 | 437595409 100 | 442651885 101 | 4470478982 102 | 4471110141 103 | 447910249 104 | 448291547 105 | 4492032921 106 | 45092961 107 | 4512714865 108 | 4520272436 109 | 4553922208 110 | 4555082379 111 | 4560029166 112 | 4584451140 113 | 4683040401 114 | 4739664721 115 | 4758145781 116 | 47618649 117 | 4774338842 118 | 4801259916 119 | 4821642 120 | 4856974482 121 | 4880083461 122 | 4970182488 123 | 5002723411 124 | 5007442 125 | 5020454673 126 | 5065140719 127 | 5083671561 128 | 5144909700 129 | 5146483815 130 | 5151536225 131 | 5188566452 132 | 5201079592 133 | 5204730083 134 | 5227275045 135 | 52381600 136 | 5301057994 137 | 539722510 138 | 5452623 139 | 56054945 140 | 59354095 141 | 642820626 142 | 658607626 143 | 79378097 144 | 815038 145 | 82161078 146 | 823016568 147 | 878985234 148 | 88094323 149 | 899545263 150 | 90800092 151 | 91328372 152 | 9545523490 153 | 955659370 154 | 1051618982 155 | 1130084326 156 | 120563545 157 | 134212 158 | 1602308 159 | 16413031 160 | 2037185414 161 | 2060241469 162 | 2080551997 163 | 2086996835 164 | 2099639490 165 | 2122067003 166 | 2201628776 167 | 2239259 168 | 2296215131 169 | 2316734819 170 | 2329110240 171 | 2339510439 172 | 2392075438 173 | 2406586388 174 | 24795717 175 | 2519293956 176 | 253915276 177 | 255360810 178 | 2751381965 179 | 2803423910 180 | 2805422179 181 | 3020248483 182 | 3116931144 183 | 3346359383 184 | 3363054468 185 | 3504938758 186 | 3532475790 187 | 3722549017 188 | 378492784 189 | 397921011 190 | 4009440741 191 | 410225851 192 | 411555970 193 | 4145388945 194 | 4239974048 195 | 4400753623 196 | 442743156 197 | 4538917191 198 | 4573422380 199 | 4906266640 200 | 507521047 201 | 5082623456 202 | 5106695994 203 | 5169701116 204 | 70037463 205 | 719902933 -------------------------------------------------------------------------------- /tools/afw_test.py: -------------------------------------------------------------------------------- 1 | #-*- coding:utf-8 -*- 2 | 3 | from __future__ import division 4 | from __future__ import absolute_import 5 | from __future__ import print_function 6 | 7 | import os 8 | import sys 9 | import torch 10 | import argparse 11 | import torch.nn as nn 12 | import torch.utils.data as data 13 | import torch.backends.cudnn as cudnn 14 | import torchvision.transforms as transforms 15 | 16 | import cv2 17 | import time 18 | import numpy as np 19 | from PIL import Image 20 | 21 | from data.config import cfg 22 | from s3fd import build_s3fd 23 | from torch.autograd import Variable 24 | from utils.augmentations import to_chw_bgr 25 | 26 | 27 | parser = argparse.ArgumentParser(description='s3fd evaluatuon afw') 28 | parser.add_argument('--model', type=str, 29 | default='weights/s3fd.pth', help='trained model') 30 | parser.add_argument('--thresh', default=0.1, type=float, 31 | help='Final confidence threshold') 32 | args = parser.parse_args() 33 | 34 | use_cuda = torch.cuda.is_available() 35 | 36 | if use_cuda: 37 | torch.set_default_tensor_type('torch.cuda.FloatTensor') 38 | else: 39 | torch.set_default_tensor_type('torch.FloatTensor') 40 | 41 | AFW_IMG_DIR = os.path.join(cfg.FACE.AFW_DIR, 'images') 42 | AFW_RESULT_DIR = os.path.join(cfg.FACE.AFW_DIR, 's3fd') 43 | AFW_RESULT_IMG_DIR = os.path.join(AFW_RESULT_DIR, 'images') 44 | 45 | if not os.path.exists(AFW_RESULT_IMG_DIR): 46 | os.makedirs(AFW_RESULT_IMG_DIR) 47 | 48 | 49 | def detect_face(net, img, thresh): 50 | height, width, _ = img.shape 51 | im_shrink = 640.0 / max(height, width) 52 | image = cv2.resize(img, None, None, fx=im_shrink, 53 | fy=im_shrink, interpolation=cv2.INTER_LINEAR).copy() 54 | 55 | x = to_chw_bgr(image) 56 | x = x.astype('float32') 57 | x -= cfg.img_mean 58 | x = x[[2, 1, 0], :, :] 59 | 60 | x = Variable(torch.from_numpy(x).unsqueeze(0)) 61 | if use_cuda: 62 | x = x.cuda() 63 | 64 | y = net(x) 65 | detections = y.data 66 | scale = torch.Tensor([img.shape[1], img.shape[0], 67 | img.shape[1], img.shape[0]]) 68 | 69 | bboxes = [] 70 | for i in range(detections.size(1)): 71 | j = 0 72 | while detections[0, i, j, 0] >= thresh: 73 | box = [] 74 | score = detections[0, i, j, 0] 75 | pt = (detections[0, i, j, 1:] * scale).cpu().numpy().astype(np.int) 76 | j += 1 77 | box += [pt[0], pt[1], pt[2], pt[3], score] 78 | box[1] += 0.2 * (box[3] - box[1] + 1) 79 | bboxes += [box] 80 | 81 | return bboxes 82 | 83 | 84 | if __name__ == '__main__': 85 | net = build_s3fd('test', cfg.NUM_CLASSES) 86 | net.load_state_dict(torch.load(args.model)) 87 | net.eval() 88 | 89 | if use_cuda: 90 | net.cuda() 91 | cudnn.benckmark = True 92 | 93 | #transform = S3FDBasicTransform(cfg.INPUT_SIZE, cfg.MEANS) 94 | 95 | counter = 0 96 | txt_out = os.path.join(AFW_RESULT_DIR, 'sfd_dets.txt') 97 | txt_in = os.path.join('./tools/afw_img_list.txt') 98 | 99 | fout = open(txt_out, 'w') 100 | fin = open(txt_in, 'r') 101 | 102 | for line in fin.readlines(): 103 | line = line.strip() 104 | img_file = os.path.join(AFW_IMG_DIR, line + '.jpg') 105 | out_file = os.path.join(AFW_RESULT_IMG_DIR, line + '.jpg') 106 | counter += 1 107 | t1 = time.time() 108 | #img = cv2.imread(img_file, cv2.IMREAD_COLOR) 109 | img = Image.open(img_file) 110 | if img.mode == 'L': 111 | img = img.convert('RGB') 112 | img = np.array(img) 113 | bboxes = detect_face(net, img, args.thresh) 114 | t2 = time.time() 115 | print('Detect %04d th image costs %.4f' % (counter, t2 - t1)) 116 | for bbox in bboxes: 117 | x1, y1, x2, y2, score = bbox 118 | fout.write('{:s} {:.3f} {:.1f} {:.1f} {:.1f} {:.1f}\n'.format( 119 | line, score, x1, y1, x2, y2)) 120 | for bbox in bboxes: 121 | x1, y1, x2, y2, score = bbox 122 | x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2) 123 | cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) 124 | cv2.imwrite(out_file, img) 125 | 126 | fout.close() 127 | fin.close() 128 | -------------------------------------------------------------------------------- /tools/anchor_matching_test.py: -------------------------------------------------------------------------------- 1 | #-*- coding:utf-8 -*- 2 | 3 | from __future__ import division 4 | from __future__ import absolute_import 5 | from __future__ import print_function 6 | 7 | import os 8 | import pickle 9 | import torch 10 | import numpy as np 11 | from data.config import cfg 12 | import torch.utils.data as data 13 | 14 | from utils.augmentations import S3FDValTransform 15 | from layers.functions import PriorBox 16 | from data.wider_face import WIDERDetection, detection_collate 17 | 18 | from layers.bbox_utils import match, match_ssd, decode 19 | 20 | import matplotlib.pyplot as plt 21 | 22 | 23 | dataset = WIDERDetection( 24 | cfg.TRAIN_FILE, transform=S3FDValTransform(cfg.INPUT_SIZE), train=False) 25 | 26 | data_loader = data.DataLoader(dataset, 64, 27 | num_workers=4, 28 | shuffle=False, 29 | collate_fn=detection_collate, 30 | pin_memory=True) 31 | 32 | anchor_boxes = PriorBox(cfg).forward() 33 | num_priors = anchor_boxes.size(0) 34 | variance = cfg.VARIANCE 35 | 36 | savepath = 'tmp' 37 | if not os.path.exists(savepath): 38 | os.makedirs(savepath) 39 | 40 | filename = os.path.join(savepath, 'match_anchor.pkl') 41 | 42 | 43 | def anchor_match_count(): 44 | anchor_scale_map = {16: 0, 32: 0, 64: 0, 128: 0, 256: 0, 512: 0} 45 | thresh = cfg.OVERLAP_THRESH 46 | sfd_scales = [] 47 | for idx, (_, target) in enumerate(data_loader): 48 | num = len(target) 49 | 50 | loc_t = torch.Tensor(num, num_priors, 4) 51 | conf_t = torch.LongTensor(num, num_priors) 52 | 53 | for index in range(num): 54 | truths = target[index][:, :-1] 55 | labels = target[index][:, -1] 56 | 57 | match(thresh, truths, anchor_boxes, 58 | variance, labels, loc_t, conf_t, index) 59 | 60 | pos = conf_t > 0 61 | pos_idx = pos.unsqueeze(pos.dim()).expand_as(loc_t) 62 | defaults = anchor_boxes.view(-1, num_priors, 63 | 4).expand_as(loc_t).contiguous().view(-1, 4).clone() 64 | loc_t = loc_t.view(-1, 4) 65 | decoded_boxes = decode(loc_t, defaults, variance) 66 | decoded_boxes = decoded_boxes.view(num, num_priors, 4) 67 | match_boxes = decoded_boxes[pos_idx].view(-1, 4) 68 | 69 | ori_boxes = match_boxes * cfg.INPUT_SIZE 70 | wh = ori_boxes[:, 2:] - ori_boxes[:, 0:2] 71 | 72 | scales = torch.sqrt(wh[:, 0] * wh[:, 1]) 73 | scales = scales.numpy().astype(np.int) 74 | print(scales.shape) 75 | 76 | sfd_scales += [scales] 77 | 78 | sfd_scales = np.concatenate(sfd_scales, axis=0) 79 | sfd_result = all_np(sfd_scales) 80 | 81 | return sfd_result 82 | 83 | 84 | def anchor_match_ssd_count(): 85 | anchor_scale_map = {16: 0, 32: 0, 64: 0, 128: 0, 256: 0, 512: 0} 86 | thresh = 0.5 87 | ssd_scales = [] 88 | for idx, (_, target) in enumerate(data_loader): 89 | num = len(target) 90 | 91 | loc_t = torch.Tensor(num, num_priors, 4) 92 | conf_t = torch.LongTensor(num, num_priors) 93 | 94 | for index in range(num): 95 | truths = target[index][:, :-1] 96 | labels = target[index][:, -1] 97 | 98 | match_ssd(thresh, truths, anchor_boxes, 99 | variance, labels, loc_t, conf_t, index) 100 | 101 | pos = conf_t > 0 102 | pos_idx = pos.unsqueeze(pos.dim()).expand_as(loc_t) 103 | defaults = anchor_boxes.view(-1, num_priors, 104 | 4).expand_as(loc_t).contiguous().view(-1, 4).clone() 105 | loc_t = loc_t.view(-1, 4) 106 | decoded_boxes = decode(loc_t, defaults, variance) 107 | decoded_boxes = decoded_boxes.view(num, num_priors, 4) 108 | match_boxes = decoded_boxes[pos_idx].view(-1, 4) 109 | 110 | ori_boxes = match_boxes * cfg.INPUT_SIZE 111 | wh = ori_boxes[:, 2:] - ori_boxes[:, 0:2] 112 | 113 | scales = torch.sqrt(wh[:, 0] * wh[:, 1]) 114 | scales = scales.numpy().astype(np.int) 115 | print(scales.shape) 116 | 117 | ssd_scales += [scales] 118 | 119 | ssd_scales = np.concatenate(ssd_scales, axis=0) 120 | ssd_result = all_np(ssd_scales) 121 | return ssd_result 122 | 123 | 124 | def all_np(arr): 125 | arr = np.array(arr) 126 | key = np.unique(arr) 127 | result = {} 128 | for k in key: 129 | mask = (arr == k) 130 | arr_new = arr[mask] 131 | v = arr_new.size 132 | result[k] = v 133 | return result 134 | 135 | 136 | def save_pkl(): 137 | sfd_count = anchor_match_count() 138 | ssd_count = anchor_match_ssd_count() 139 | 140 | result = {'sfd': sfd_count, 'ssd': ssd_count} 141 | file = open(filename, 'wb') 142 | pickle.dump(result, file) 143 | file.close() 144 | 145 | 146 | def plot_anchor_match(): 147 | if not os.path.exists(filename): 148 | save_pkl() 149 | 150 | with open(filename, 'rb') as f: 151 | result = pickle.load(f) 152 | 153 | sfd_res = result['sfd'] 154 | ssd_res = result['ssd'] 155 | 156 | sfd_count = [] 157 | ssd_count = [] 158 | 159 | frames = range(0, 660) 160 | 161 | sfd_feat_count = np.zeros(len(frames)) 162 | ssd_feat_count = np.zeros(len(frames)) 163 | feat_maps = np.array([16, 32, 64, 128, 256, 512]) 164 | 165 | for i in frames: 166 | if i in sfd_res.keys(): 167 | sfd_count += [sfd_res[i]] 168 | else: 169 | sfd_count += [0] 170 | if i in ssd_res.keys(): 171 | ssd_count += [ssd_res[i]] 172 | else: 173 | ssd_count += [0] 174 | 175 | sfd_count = np.array(sfd_count) 176 | ssd_count = np.array(ssd_count) 177 | 178 | for feat in feat_maps: 179 | if feat in sfd_res.keys(): 180 | sfd_feat_count[feat] = sfd_res[feat] 181 | if feat in ssd_res.keys(): 182 | ssd_feat_count[feat] = ssd_res[feat] 183 | 184 | n = 280 185 | plt.plot(frames[:n], sfd_count[:n], 'r', label='sfd matching method') 186 | plt.plot(frames[:n], sfd_feat_count[:n], 'b', 187 | label='sfd in [16,32,64...] match') 188 | 189 | plt.plot(frames[:n], ssd_count[:n], 'g-', label='ssd matching method') 190 | plt.plot(frames[:n], ssd_feat_count[:n], 'c-', 191 | label='ssd in [16,32,64...] match') 192 | 193 | fig1 = plt.figure(1) 194 | axes = plt.subplot(111) 195 | axes.set_yticks([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]) 196 | axes.grid(True) 197 | plt.legend(loc="upper right") 198 | 199 | plt.ylabel('Num of match anchor ratio') # set ystick label 200 | plt.xlabel('Scale of face') # set xstck label 201 | 202 | plt.show() 203 | 204 | 205 | if __name__ == '__main__': 206 | plot_anchor_match() 207 | -------------------------------------------------------------------------------- /tools/detect.py: -------------------------------------------------------------------------------- 1 | #-*- coding:utf-8 -*- 2 | 3 | from __future__ import division 4 | from __future__ import absolute_import 5 | from __future__ import print_function 6 | 7 | import os 8 | import torch 9 | import argparse 10 | import torch.nn as nn 11 | import torch.utils.data as data 12 | import torch.backends.cudnn as cudnn 13 | import torchvision.transforms as transforms 14 | 15 | import cv2 16 | import time 17 | import numpy as np 18 | 19 | from data.config import cfg 20 | from s3fd import build_s3fd 21 | from torch.autograd import Variable 22 | from utils.augmentations import S3FDBasicTransform 23 | 24 | 25 | parser = argparse.ArgumentParser(description='s3df evaluatuon fddb') 26 | parser.add_argument('--trained_model', type=str, 27 | default='weights/s3fd.pth', help='trained model') 28 | parser.add_argument('--thresh', default=0.1, type=float, 29 | help='Final confidence threshold') 30 | args = parser.parse_args() 31 | 32 | use_cuda = torch.cuda.is_available() 33 | 34 | if use_cuda: 35 | torch.set_default_tensor_type('torch.cuda.FloatTensor') 36 | else: 37 | torch.set_default_tensor_type('torch.FloatTensor') 38 | 39 | 40 | net = build_s3fd('train', cfg.INPUT_SIZE, cfg.NUM_CLASSES) 41 | net.load_state_dict(torch.load(args.trained_model)) 42 | net.eval() 43 | 44 | 45 | def dyna_anchor(imh,imw): 46 | pass 47 | -------------------------------------------------------------------------------- /tools/fddb_test.py: -------------------------------------------------------------------------------- 1 | #-*- coding:utf-8 -*- 2 | 3 | from __future__ import division 4 | from __future__ import absolute_import 5 | from __future__ import print_function 6 | 7 | import os 8 | import sys 9 | import torch 10 | import argparse 11 | import torch.nn as nn 12 | import torch.utils.data as data 13 | import torch.backends.cudnn as cudnn 14 | import torchvision.transforms as transforms 15 | 16 | import cv2 17 | import time 18 | import numpy as np 19 | from PIL import Image 20 | 21 | from data.config import cfg 22 | from s3fd import build_s3fd 23 | from torch.autograd import Variable 24 | from utils.augmentations import to_chw_bgr 25 | 26 | parser = argparse.ArgumentParser(description='s3fd evaluatuon fddb') 27 | parser.add_argument('--model', type=str, 28 | default='weights/s3fd.pth', help='trained model') 29 | parser.add_argument('--thresh', default=0.1, type=float, 30 | help='Final confidence threshold') 31 | args = parser.parse_args() 32 | 33 | 34 | use_cuda = torch.cuda.is_available() 35 | 36 | if use_cuda: 37 | torch.set_default_tensor_type('torch.cuda.FloatTensor') 38 | else: 39 | torch.set_default_tensor_type('torch.FloatTensor') 40 | 41 | 42 | FDDB_IMG_DIR = os.path.join(cfg.FACE.FDDB_DIR, 'images') 43 | FDDB_FOLD_DIR = os.path.join(cfg.FACE.FDDB_DIR, 'FDDB-folds') 44 | FDDB_RESULT_DIR = os.path.join(cfg.FACE.FDDB_DIR, 's3fd') 45 | FDDB_RESULT_IMG_DIR = os.path.join(FDDB_RESULT_DIR, 'images') 46 | 47 | if not os.path.exists(FDDB_RESULT_IMG_DIR): 48 | os.makedirs(FDDB_RESULT_IMG_DIR) 49 | 50 | 51 | def detect_face(net, img, thresh): 52 | height, width, _ = img.shape 53 | x = to_chw_bgr(img) 54 | x = x.astype('float32') 55 | x -= cfg.img_mean 56 | x = x[[2, 1, 0], :, :] 57 | 58 | x = Variable(torch.from_numpy(x).unsqueeze(0)) 59 | if use_cuda: 60 | x = x.cuda() 61 | 62 | y = net(x) 63 | detections = y.data 64 | scale = torch.Tensor([img.shape[1], img.shape[0], 65 | img.shape[1], img.shape[0]]) 66 | 67 | bboxes = [] 68 | for i in range(detections.size(1)): 69 | j = 0 70 | while detections[0, i, j, 0] >= thresh: 71 | box = [] 72 | score = detections[0, i, j, 0] 73 | pt = (detections[0, i, j, 1:] * scale).cpu().numpy().astype(np.int) 74 | j += 1 75 | box += [pt[0], pt[1], pt[2] - pt[0], pt[3] - pt[1], score] 76 | bboxes += [box] 77 | 78 | return bboxes 79 | 80 | 81 | if __name__ == '__main__': 82 | net = build_s3fd('test', cfg.NUM_CLASSES) 83 | net.load_state_dict(torch.load(args.model)) 84 | net.eval() 85 | 86 | if use_cuda: 87 | net.cuda() 88 | cudnn.benckmark = True 89 | 90 | #transform = S3FDBasicTransform(cfg.INPUT_SIZE, cfg.MEANS) 91 | 92 | counter = 0 93 | 94 | for i in range(10): 95 | txt_in = os.path.join(FDDB_FOLD_DIR, 'FDDB-fold-%02d.txt' % (i + 1)) 96 | txt_out = os.path.join(FDDB_RESULT_DIR, 'fold-%02d-out.txt' % (i + 1)) 97 | answer_in = os.path.join( 98 | FDDB_FOLD_DIR, 'FDDB-fold-%02d-ellipseList.txt' % (i + 1)) 99 | with open(txt_in, 'r') as fr: 100 | lines = fr.readlines() 101 | fout = open(txt_out, 'w') 102 | ain = open(answer_in, 'r') 103 | for line in lines: 104 | line = line.strip() 105 | img_file = os.path.join(FDDB_IMG_DIR, line + '.jpg') 106 | out_file = os.path.join( 107 | FDDB_RESULT_IMG_DIR, line.replace('/', '_') + '.jpg') 108 | counter += 1 109 | t1 = time.time() 110 | #img = cv2.imread(img_file, cv2.IMREAD_COLOR) 111 | img = Image.open(img_file) 112 | if img.mode == 'L': 113 | img = img.convert('RGB') 114 | img = np.array(img) 115 | bboxes = detect_face(net, img, args.thresh) 116 | t2 = time.time() 117 | print('Detect %04d th image costs %.4f' % (counter, t2 - t1)) 118 | fout.write('%s\n' % line) 119 | fout.write('%d\n' % len(bboxes)) 120 | for bbox in bboxes: 121 | x1, y1, w, h, score = bbox 122 | fout.write('%d %d %d %d %lf\n' % (x1, y1, w, h, score)) 123 | ain.readline() 124 | n = int(ain.readline().strip()) 125 | for i in range(n): 126 | line = ain.readline().strip() 127 | line_data = [float(_) for _ in line.split(' ')[:5]] 128 | major_axis_radius, minor_axis_radius, angle, center_x, center_y = line_data 129 | angle = angle / 3.1415926 * 180. 130 | center_x, center_y = int(center_x), int(center_y) 131 | major_axis_radius, minor_axis_radius = int( 132 | major_axis_radius), int(minor_axis_radius) 133 | cv2.ellipse(img, (center_x, center_y), (major_axis_radius, 134 | minor_axis_radius), angle, 0, 360, (255, 0, 0), 2) 135 | 136 | for bbox in bboxes: 137 | x1, y1, w, h, score = bbox 138 | x1, y1, x2, y2 = int(x1), int(y1), int(x1 + w), int(y1 + h) 139 | cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) 140 | cv2.imwrite(out_file, img) 141 | fout.close() 142 | ain.close() 143 | -------------------------------------------------------------------------------- /tools/pascal_test.py: -------------------------------------------------------------------------------- 1 | #-*- coding:utf-8 -*- 2 | 3 | from __future__ import division 4 | from __future__ import absolute_import 5 | from __future__ import print_function 6 | 7 | import os 8 | import sys 9 | import torch 10 | import argparse 11 | import torch.nn as nn 12 | import torch.utils.data as data 13 | import torch.backends.cudnn as cudnn 14 | import torchvision.transforms as transforms 15 | 16 | import cv2 17 | import time 18 | import numpy as np 19 | from PIL import Image 20 | 21 | from data.config import cfg 22 | from s3fd import build_s3fd 23 | from torch.autograd import Variable 24 | from utils.augmentations import to_chw_bgr 25 | 26 | 27 | parser = argparse.ArgumentParser(description='s3df evaluatuon pascal') 28 | parser.add_argument('--model', type=str, 29 | default='weights/s3fd.pth', help='trained model') 30 | parser.add_argument('--thresh', default=0.1, type=float, 31 | help='Final confidence threshold') 32 | args = parser.parse_args() 33 | 34 | use_cuda = torch.cuda.is_available() 35 | 36 | if use_cuda: 37 | torch.set_default_tensor_type('torch.cuda.FloatTensor') 38 | else: 39 | torch.set_default_tensor_type('torch.FloatTensor') 40 | 41 | PASCAL_IMG_DIR = os.path.join(cfg.FACE.PASCAL_DIR, 'images') 42 | PASCAL_RESULT_DIR = os.path.join(cfg.FACE.PASCAL_DIR, 's3fd') 43 | PASCAL_RESULT_IMG_DIR = os.path.join(PASCAL_RESULT_DIR, 'images') 44 | 45 | if not os.path.exists(PASCAL_RESULT_IMG_DIR): 46 | os.makedirs(PASCAL_RESULT_IMG_DIR) 47 | 48 | 49 | def detect_face(net, img, thresh): 50 | height, width, _ = img.shape 51 | im_shrink = 640.0 / max(height, width) 52 | image = cv2.resize(img, None, None, fx=im_shrink, 53 | fy=im_shrink, interpolation=cv2.INTER_LINEAR).copy() 54 | 55 | x = to_chw_bgr(image) 56 | x = x.astype('float32') 57 | x -= cfg.img_mean 58 | x = x[[2, 1, 0], :, :] 59 | 60 | x = Variable(torch.from_numpy(x).unsqueeze(0)) 61 | if use_cuda: 62 | x = x.cuda() 63 | 64 | y = net(x) 65 | detections = y.data 66 | scale = torch.Tensor([img.shape[1], img.shape[0], 67 | img.shape[1], img.shape[0]]) 68 | 69 | bboxes = [] 70 | for i in range(detections.size(1)): 71 | j = 0 72 | while detections[0, i, j, 0] >= thresh: 73 | box = [] 74 | score = detections[0, i, j, 0] 75 | pt = (detections[0, i, j, 1:] * scale).cpu().numpy().astype(np.int) 76 | j += 1 77 | box += [pt[0], pt[1], pt[2], pt[3], score] 78 | box[1] += 0.2 * (box[3] - box[1] + 1) 79 | bboxes += [box] 80 | 81 | return bboxes 82 | 83 | 84 | if __name__ == '__main__': 85 | net = build_s3fd('test', cfg.NUM_CLASSES) 86 | net.load_state_dict(torch.load(args.model)) 87 | net.eval() 88 | 89 | if use_cuda: 90 | net.cuda() 91 | cudnn.benckmark = True 92 | 93 | #transform = S3FDBasicTransform(cfg.INPUT_SIZE, cfg.MEANS) 94 | 95 | counter = 0 96 | txt_out = os.path.join(PASCAL_RESULT_DIR, 'sfd_dets.txt') 97 | txt_in = os.path.join('./tools/pascal_img_list.txt') 98 | 99 | fout = open(txt_out, 'w') 100 | fin = open(txt_in, 'r') 101 | 102 | for line in fin.readlines(): 103 | line = line.strip() 104 | img_file = os.path.join(PASCAL_IMG_DIR, line) 105 | out_file = os.path.join(PASCAL_RESULT_IMG_DIR, line) 106 | counter += 1 107 | t1 = time.time() 108 | #img = cv2.imread(img_file, cv2.IMREAD_COLOR) 109 | img = Image.open(img_file) 110 | if img.mode == 'L': 111 | img = img.convert('RGB') 112 | img = np.array(img) 113 | bboxes = detect_face(net, img, args.thresh) 114 | t2 = time.time() 115 | print('Detect %04d th image costs %.4f' % (counter, t2 - t1)) 116 | for bbox in bboxes: 117 | x1, y1, x2, y2, score = bbox 118 | fout.write('{:s} {:.3f} {:.1f} {:.1f} {:.1f} {:.1f}\n'.format( 119 | line, score, x1, y1, x2, y2)) 120 | for bbox in bboxes: 121 | x1, y1, x2, y2, score = bbox 122 | x1, y1, x2, y2 = int(x1), int(y1), int(x2), int(y2) 123 | cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) 124 | cv2.imwrite(out_file, img) 125 | 126 | fout.close() 127 | fin.close() 128 | -------------------------------------------------------------------------------- /tools/wider_test.py: -------------------------------------------------------------------------------- 1 | #-*- coding:utf-8 -*- 2 | 3 | from __future__ import division 4 | from __future__ import absolute_import 5 | from __future__ import print_function 6 | 7 | import os 8 | import torch 9 | import argparse 10 | import torch.nn as nn 11 | import torch.utils.data as data 12 | import torch.backends.cudnn as cudnn 13 | import torchvision.transforms as transforms 14 | import os.path as osp 15 | 16 | import cv2 17 | import time 18 | import numpy as np 19 | from PIL import Image 20 | import scipy.io as sio 21 | 22 | from data.config import cfg 23 | from s3fd import build_s3fd 24 | from torch.autograd import Variable 25 | from utils.augmentations import to_chw_bgr 26 | 27 | from tqdm import tqdm 28 | 29 | ''' 30 | parser = argparse.ArgumentParser(description='s3fd evaluatuon wider') 31 | parser.add_argument('--model', type=str, 32 | default='weights/s3fd.pth', help='trained model') 33 | parser.add_argument('--thresh', default=0.05, type=float, 34 | help='Final confidence threshold') 35 | args = parser.parse_args() 36 | ''' 37 | 38 | thresh = 0.05 39 | 40 | use_cuda = torch.cuda.is_available() 41 | 42 | if use_cuda: 43 | torch.set_default_tensor_type('torch.cuda.FloatTensor') 44 | else: 45 | torch.set_default_tensor_type('torch.FloatTensor') 46 | 47 | 48 | def detect_face(net, img, shrink): 49 | if shrink != 1: 50 | img = cv2.resize(img, None, None, fx=shrink, fy=shrink, 51 | interpolation=cv2.INTER_LINEAR) 52 | 53 | x = to_chw_bgr(img) 54 | x = x.astype('float32') 55 | x -= cfg.img_mean 56 | x = x[[2, 1, 0], :, :] 57 | 58 | x = Variable(torch.from_numpy(x).unsqueeze(0)) 59 | 60 | if use_cuda: 61 | x = x.cuda() 62 | # print(x.size()) 63 | y = net(x) 64 | detections = y.data 65 | detections = detections.cpu().numpy() 66 | 67 | det_conf = detections[0, 1, :, 0] 68 | det_xmin = img.shape[1] * detections[0, 1, :, 1] / shrink 69 | det_ymin = img.shape[0] * detections[0, 1, :, 2] / shrink 70 | det_xmax = img.shape[1] * detections[0, 1, :, 3] / shrink 71 | det_ymax = img.shape[0] * detections[0, 1, :, 4] / shrink 72 | det = np.column_stack((det_xmin, det_ymin, det_xmax, det_ymax, det_conf)) 73 | 74 | keep_index = np.where(det[:, 4] >= thresh)[0] 75 | det = det[keep_index, :] 76 | 77 | return det 78 | 79 | 80 | def flip_test(net, image, shrink): 81 | image_f = cv2.flip(image, 1) 82 | det_f = detect_face(net, image_f, shrink) 83 | 84 | det_t = np.zeros(det_f.shape) 85 | det_t[:, 0] = image.shape[1] - det_f[:, 2] 86 | det_t[:, 1] = det_f[:, 1] 87 | det_t[:, 2] = image.shape[1] - det_f[:, 0] 88 | det_t[:, 3] = det_f[:, 3] 89 | det_t[:, 4] = det_f[:, 4] 90 | return det_t 91 | 92 | 93 | def multi_scale_test(net, image, max_im_shrink): 94 | # shrink detecting and shrink only detect big face 95 | st = 0.5 if max_im_shrink >= 0.75 else 0.5 * max_im_shrink 96 | det_s = detect_face(net, image, st) 97 | index = np.where(np.maximum( 98 | det_s[:, 2] - det_s[:, 0] + 1, det_s[:, 3] - det_s[:, 1] + 1) > 30)[0] 99 | det_s = det_s[index, :] 100 | 101 | # enlarge one times 102 | bt = min(2, max_im_shrink) if max_im_shrink > 1 else ( 103 | st + max_im_shrink) / 2 104 | det_b = detect_face(net, image, bt) 105 | 106 | # enlarge small image x times for small face 107 | if max_im_shrink > 2: 108 | bt *= 2 109 | while bt < max_im_shrink: 110 | det_b = np.row_stack((det_b, detect_face(net, image, bt))) 111 | bt *= 2 112 | det_b = np.row_stack((det_b, detect_face(net, image, max_im_shrink))) 113 | 114 | # enlarge only detect small face 115 | if bt > 1: 116 | index = np.where(np.minimum( 117 | det_b[:, 2] - det_b[:, 0] + 1, det_b[:, 3] - det_b[:, 1] + 1) < 100)[0] 118 | det_b = det_b[index, :] 119 | else: 120 | index = np.where(np.maximum( 121 | det_b[:, 2] - det_b[:, 0] + 1, det_b[:, 3] - det_b[:, 1] + 1) > 30)[0] 122 | det_b = det_b[index, :] 123 | 124 | return det_s, det_b 125 | 126 | 127 | def bbox_vote(det): 128 | order = det[:, 4].ravel().argsort()[::-1] 129 | det = det[order, :] 130 | while det.shape[0] > 0: 131 | # IOU 132 | area = (det[:, 2] - det[:, 0] + 1) * (det[:, 3] - det[:, 1] + 1) 133 | xx1 = np.maximum(det[0, 0], det[:, 0]) 134 | yy1 = np.maximum(det[0, 1], det[:, 1]) 135 | xx2 = np.minimum(det[0, 2], det[:, 2]) 136 | yy2 = np.minimum(det[0, 3], det[:, 3]) 137 | w = np.maximum(0.0, xx2 - xx1 + 1) 138 | h = np.maximum(0.0, yy2 - yy1 + 1) 139 | inter = w * h 140 | o = inter / (area[0] + area[:] - inter) 141 | 142 | # get needed merge det and delete these det 143 | merge_index = np.where(o >= 0.3)[0] 144 | det_accu = det[merge_index, :] 145 | det = np.delete(det, merge_index, 0) 146 | 147 | if merge_index.shape[0] <= 1: 148 | continue 149 | det_accu[:, 0:4] = det_accu[:, 0:4] * np.tile(det_accu[:, -1:], (1, 4)) 150 | max_score = np.max(det_accu[:, 4]) 151 | det_accu_sum = np.zeros((1, 5)) 152 | det_accu_sum[:, 0:4] = np.sum( 153 | det_accu[:, 0:4], axis=0) / np.sum(det_accu[:, -1:]) 154 | det_accu_sum[:, 4] = max_score 155 | try: 156 | dets = np.row_stack((dets, det_accu_sum)) 157 | except: 158 | dets = det_accu_sum 159 | 160 | dets = dets[0:750, :] 161 | return dets 162 | 163 | 164 | def get_data(): 165 | subset = 'val' 166 | if subset is 'val': 167 | wider_face = sio.loadmat( 168 | './eval_tools/wider_face_val.mat') 169 | else: 170 | wider_face = sio.loadmat( 171 | './eval_tools/wider_face_test.mat') 172 | event_list = wider_face['event_list'] 173 | file_list = wider_face['file_list'] 174 | del wider_face 175 | 176 | imgs_path = os.path.join( 177 | cfg.FACE.WIDER_DIR, 'WIDER_{}'.format(subset), 'images') 178 | save_path = 'eval_tools/s3fd_{}'.format(subset) 179 | 180 | return event_list, file_list, imgs_path, save_path 181 | 182 | 183 | def eval_wider(model_name): 184 | event_list, file_list, imgs_path, save_path = get_data() 185 | cfg.USE_NMS = True 186 | net = build_s3fd('test', cfg.NUM_CLASSES) 187 | net.load_state_dict(torch.load(model_name)) 188 | net.eval() 189 | 190 | if use_cuda: 191 | net.cuda() 192 | cudnn.benckmark = True 193 | 194 | # transform = S3FDBasicTransform(cfg.INPUT_SIZE, cfg.MEANS) 195 | 196 | counter = 0 197 | 198 | for index, event in enumerate(tqdm(event_list)): 199 | filelist = file_list[index][0] 200 | path = os.path.join(save_path, event[0][0].encode('utf-8')) 201 | if not os.path.exists(path): 202 | os.makedirs(path) 203 | 204 | for num, file in enumerate(filelist): 205 | im_name = file[0][0].encode('utf-8') 206 | in_file = os.path.join(imgs_path, event[0][0], im_name[:] + '.jpg') 207 | # img = cv2.imread(in_file) 208 | img = Image.open(in_file) 209 | if img.mode == 'L': 210 | img = img.convert('RGB') 211 | img = np.array(img) 212 | 213 | # max_im_shrink = (0x7fffffff / 577.0 / 214 | # (img.shape[0] * img.shape[1])) ** 0.5 215 | 216 | max_im_shrink = np.sqrt( 217 | 1700 * 1200 / (img.shape[0] * img.shape[1])) 218 | 219 | shrink = max_im_shrink if max_im_shrink < 1 else 1 220 | counter += 1 221 | 222 | t1 = time.time() 223 | det0 = detect_face(net, img, shrink) 224 | 225 | det1 = flip_test(net, img, shrink) # flip test 226 | [det2, det3] = multi_scale_test(net, img, max_im_shrink) 227 | 228 | det = np.row_stack((det0, det1, det2, det3)) 229 | dets = bbox_vote(det) 230 | 231 | t2 = time.time() 232 | #print('Detect %04d th image costs %.4f' % (counter, t2 - t1)) 233 | 234 | fout = open(osp.join(save_path, event[0][0].encode('utf-8'), im_name + '.txt'), 'w') 235 | fout.write('{:s}\n'.format(event[0][0].encode('utf-8') + '/' + im_name + '.jpg')) 236 | fout.write('{:d}\n'.format(dets.shape[0])) 237 | for i in xrange(dets.shape[0]): 238 | xmin = dets[i][0] 239 | ymin = dets[i][1] 240 | xmax = dets[i][2] 241 | ymax = dets[i][3] 242 | score = dets[i][4] 243 | fout.write('{:.1f} {:.1f} {:.1f} {:.1f} {:.3f}\n' 244 | .format(xmin, ymin, (xmax - xmin + 1), (ymax - ymin + 1), score)) 245 | 246 | 247 | 248 | -------------------------------------------------------------------------------- /utils/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /weights/EXTD_32.pth: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/weights/EXTD_32.pth -------------------------------------------------------------------------------- /weights/EXTD_48.pth: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/weights/EXTD_48.pth -------------------------------------------------------------------------------- /weights/EXTD_64.pth: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clovaai/EXTD_Pytorch/e99af10f282d07054c1cf7c4b8c035084daaff78/weights/EXTD_64.pth -------------------------------------------------------------------------------- /wider_test.py: -------------------------------------------------------------------------------- 1 | #-*- coding:utf-8 -*- 2 | 3 | from __future__ import division 4 | from __future__ import absolute_import 5 | from __future__ import print_function 6 | 7 | import os 8 | import torch 9 | import argparse 10 | import torch.nn as nn 11 | import torch.utils.data as data 12 | import torch.backends.cudnn as cudnn 13 | import torchvision.transforms as transforms 14 | import os.path as osp 15 | 16 | import cv2 17 | import time 18 | import numpy as np 19 | from PIL import Image 20 | import scipy.io as sio 21 | 22 | from data.config import cfg 23 | from EXTD_64 import build_extd 24 | from torch.autograd import Variable 25 | from utils.augmentations import to_chw_bgr 26 | 27 | from eval_tools.evaluation import evaluation 28 | 29 | from tqdm import tqdm 30 | 31 | ''' 32 | parser = argparse.ArgumentParser(description='s3fd evaluatuon wider') 33 | parser.add_argument('--model', type=str, 34 | default='weights/EXTD_48.pth', help='trained model') 35 | parser.add_argument('--thresh', default=0.05, type=float, 36 | help='Final confidence threshold') 37 | args = parser.parse_args() 38 | ''' 39 | 40 | thresh = 0.05 41 | 42 | use_cuda = torch.cuda.is_available() 43 | 44 | if use_cuda: 45 | torch.set_default_tensor_type('torch.cuda.FloatTensor') 46 | else: 47 | torch.set_default_tensor_type('torch.FloatTensor') 48 | 49 | 50 | def detect_face(net, img, shrink): 51 | if shrink != 1: 52 | img = cv2.resize(img, None, None, fx=shrink, fy=shrink, 53 | interpolation=cv2.INTER_LINEAR) 54 | 55 | x = to_chw_bgr(img) 56 | x = x.astype('float32') 57 | x -= cfg.img_mean 58 | x = x[[2, 1, 0], :, :] 59 | 60 | x = Variable(torch.from_numpy(x).unsqueeze(0)) 61 | 62 | if use_cuda: 63 | x = x.cuda() 64 | # print(x.size()) 65 | y = net(x) 66 | detections = y.data 67 | detections = detections.cpu().numpy() 68 | 69 | det_conf = detections[0, 1, :, 0] 70 | det_xmin = img.shape[1] * detections[0, 1, :, 1] / shrink 71 | det_ymin = img.shape[0] * detections[0, 1, :, 2] / shrink 72 | det_xmax = img.shape[1] * detections[0, 1, :, 3] / shrink 73 | det_ymax = img.shape[0] * detections[0, 1, :, 4] / shrink 74 | det = np.column_stack((det_xmin, det_ymin, det_xmax, det_ymax, det_conf)) 75 | 76 | keep_index = np.where(det[:, 4] >= thresh)[0] 77 | det = det[keep_index, :] 78 | 79 | return det 80 | 81 | 82 | def flip_test(net, image, shrink): 83 | image_f = cv2.flip(image, 1) 84 | det_f = detect_face(net, image_f, shrink) 85 | 86 | det_t = np.zeros(det_f.shape) 87 | det_t[:, 0] = image.shape[1] - det_f[:, 2] 88 | det_t[:, 1] = det_f[:, 1] 89 | det_t[:, 2] = image.shape[1] - det_f[:, 0] 90 | det_t[:, 3] = det_f[:, 3] 91 | det_t[:, 4] = det_f[:, 4] 92 | return det_t 93 | 94 | 95 | def multi_scale_test(net, image, max_im_shrink): 96 | # shrink detecting and shrink only detect big face 97 | st = 0.5 if max_im_shrink >= 0.75 else 0.5 * max_im_shrink 98 | det_s = detect_face(net, image, st) 99 | index = np.where(np.maximum( 100 | det_s[:, 2] - det_s[:, 0] + 1, det_s[:, 3] - det_s[:, 1] + 1) > 30)[0] 101 | det_s = det_s[index, :] 102 | 103 | # enlarge one times 104 | bt = min(2, max_im_shrink) if max_im_shrink > 1 else ( 105 | st + max_im_shrink) / 2 106 | det_b = detect_face(net, image, bt) 107 | 108 | # enlarge small image x times for small face 109 | if max_im_shrink > 2: 110 | bt *= 2 111 | while bt < max_im_shrink: 112 | det_b = np.row_stack((det_b, detect_face(net, image, bt))) 113 | bt *= 2 114 | det_b = np.row_stack((det_b, detect_face(net, image, max_im_shrink))) 115 | 116 | # enlarge only detect small face 117 | if bt > 1: 118 | index = np.where(np.minimum( 119 | det_b[:, 2] - det_b[:, 0] + 1, det_b[:, 3] - det_b[:, 1] + 1) < 100)[0] 120 | det_b = det_b[index, :] 121 | else: 122 | index = np.where(np.maximum( 123 | det_b[:, 2] - det_b[:, 0] + 1, det_b[:, 3] - det_b[:, 1] + 1) > 30)[0] 124 | det_b = det_b[index, :] 125 | 126 | return det_s, det_b 127 | 128 | 129 | def bbox_vote(det): 130 | order = det[:, 4].ravel().argsort()[::-1] 131 | det = det[order, :] 132 | while det.shape[0] > 0: 133 | # IOU 134 | area = (det[:, 2] - det[:, 0] + 1) * (det[:, 3] - det[:, 1] + 1) 135 | xx1 = np.maximum(det[0, 0], det[:, 0]) 136 | yy1 = np.maximum(det[0, 1], det[:, 1]) 137 | xx2 = np.minimum(det[0, 2], det[:, 2]) 138 | yy2 = np.minimum(det[0, 3], det[:, 3]) 139 | w = np.maximum(0.0, xx2 - xx1 + 1) 140 | h = np.maximum(0.0, yy2 - yy1 + 1) 141 | inter = w * h 142 | o = inter / (area[0] + area[:] - inter) 143 | 144 | # get needed merge det and delete these det 145 | merge_index = np.where(o >= 0.3)[0] 146 | det_accu = det[merge_index, :] 147 | det = np.delete(det, merge_index, 0) 148 | 149 | if merge_index.shape[0] <= 1: 150 | continue 151 | det_accu[:, 0:4] = det_accu[:, 0:4] * np.tile(det_accu[:, -1:], (1, 4)) 152 | max_score = np.max(det_accu[:, 4]) 153 | det_accu_sum = np.zeros((1, 5)) 154 | det_accu_sum[:, 0:4] = np.sum( 155 | det_accu[:, 0:4], axis=0) / np.sum(det_accu[:, -1:]) 156 | det_accu_sum[:, 4] = max_score 157 | try: 158 | dets = np.row_stack((dets, det_accu_sum)) 159 | except: 160 | dets = det_accu_sum 161 | 162 | dets = dets[0:750, :] 163 | return dets 164 | 165 | 166 | def get_data(): 167 | subset = 'val' 168 | if subset is 'val': 169 | wider_face = sio.loadmat( 170 | './eval_tools/wider_face_val.mat') 171 | else: 172 | wider_face = sio.loadmat( 173 | './eval_tools/wider_face_test.mat') 174 | event_list = wider_face['event_list'] 175 | file_list = wider_face['file_list'] 176 | del wider_face 177 | 178 | imgs_path = os.path.join( 179 | cfg.FACE.WIDER_DIR, 'WIDER_{}'.format(subset), 'images') 180 | save_path = 'eval_tools/s3fd_{}'.format(subset) 181 | 182 | return event_list, file_list, imgs_path, save_path 183 | 184 | 185 | def eval_wider(model_name): 186 | event_list, file_list, imgs_path, save_path = get_data() 187 | cfg.USE_NMS = True 188 | 189 | # with torch.no_grad(): 190 | net = build_extd('test', cfg.NUM_CLASSES) 191 | # print(net) 192 | print(torch.load(model_name).keys()) 193 | net.load_state_dict(torch.load(model_name), strict=True) 194 | net.eval() 195 | with torch.no_grad(): 196 | if use_cuda: 197 | net.cuda() 198 | cudnn.benckmark = True 199 | 200 | # transform = S3FDBasicTransform(cfg.INPUT_SIZE, cfg.MEANS) 201 | 202 | counter = 0 203 | 204 | for index, event in enumerate(tqdm(event_list)): 205 | filelist = file_list[index][0] 206 | path = os.path.join(save_path, event[0][0]) 207 | if not os.path.exists(path): 208 | os.makedirs(path) 209 | 210 | for num, file in enumerate(filelist): 211 | # print(file) 212 | im_name = file[0][0] 213 | in_file = os.path.join(imgs_path, event[0][0], im_name[:] + '.jpg') 214 | # img = cv2.imread(in_file) 215 | img = Image.open(in_file) 216 | if img.mode == 'L': 217 | img = img.convert('RGB') 218 | img = np.array(img) 219 | 220 | # max_im_shrink = (0x7fffffff / 577.0 / 221 | # (img.shape[0] * img.shape[1])) ** 0.5 222 | 223 | max_im_shrink = np.sqrt( 224 | 1700 * 1200 / (img.shape[0] * img.shape[1])) 225 | 226 | shrink = max_im_shrink if max_im_shrink < 1 else 1 227 | counter += 1 228 | 229 | t1 = time.time() 230 | det0 = detect_face(net, img, shrink) 231 | 232 | det1 = flip_test(net, img, shrink) # flip test 233 | [det2, det3] = multi_scale_test(net, img, max_im_shrink) 234 | 235 | det = np.row_stack((det0, det1, det2, det3)) 236 | #det = np.row_stack((det0, det1)) 237 | dets = bbox_vote(det) 238 | 239 | t2 = time.time() 240 | # print('Detect %04d th image costs %.4f' % (counter, t2 - t1)) 241 | 242 | fout = open(osp.join(save_path, event[0][0], im_name + '.txt'), 'w') 243 | fout.write('{:s}\n'.format(event[0][0] + '/' + im_name + '.jpg')) 244 | fout.write('{:d}\n'.format(dets.shape[0])) 245 | for i in range(dets.shape[0]): 246 | xmin = dets[i][0] 247 | ymin = dets[i][1] 248 | xmax = dets[i][2] 249 | ymax = dets[i][3] 250 | score = dets[i][4] 251 | fout.write('{:.1f} {:.1f} {:.1f} {:.1f} {:.3f}\n' 252 | .format(xmin, ymin, (xmax - xmin + 1), (ymax - ymin + 1), score)) 253 | 254 | #print evaluation 255 | #evaluation() 256 | 257 | 258 | 259 | if __name__ == '__main__': 260 | #evaluation() 261 | eval_wider('./weights/EXTD_64.pth') 262 | --------------------------------------------------------------------------------