├── .gitignore ├── CASIA ├── README.md └── align_CASIA.py ├── LFW ├── README.md ├── convert_mx2py.py ├── models │ ├── AMSoftmax │ │ ├── deploy.prototxt │ │ ├── face_deploy_mirror_normalize.prototxt │ │ └── face_train_test.prototxt │ ├── arcface │ │ └── model.prototxt │ ├── centerface │ │ └── face_deploy.prototxt │ ├── mobilefacenet │ │ └── mobilefacenet-res2-6-10-2-dim128-opencv.prototxt │ └── sphereface │ │ └── sphereface_deploy.prototxt ├── plot.py ├── run_verify.py ├── test_lfw.py └── verification.py ├── Megaface ├── README.md ├── align_facescrub.py ├── align_megaface.py ├── config.conf.example ├── extract_feature_list.py ├── facescrub_80_landmark5.json ├── facescrub_landmark.json ├── matio.py ├── plot.py └── run_test.py ├── README.md ├── facealign ├── MtcnnPycaffe.py ├── README.md ├── alignment.py └── model │ ├── det1.caffemodel │ ├── det1.prototxt │ ├── det2.caffemodel │ ├── det2.prototxt │ ├── det3.caffemodel │ ├── det3.prototxt │ ├── det4.caffemodel │ └── det4.prototxt └── util ├── caffe_extractor.py ├── config.py ├── distance.py ├── fileutil.py └── logfile.py /.gitignore: -------------------------------------------------------------------------------- 1 | ## General 2 | ## Private config 3 | *.ini 4 | *.bat 5 | Megaface/*.png 6 | 7 | # Compiled Object files 8 | *.slo 9 | *.lo 10 | *.o 11 | *.cuo 12 | 13 | # Compiled Dynamic libraries 14 | *.so 15 | *.dylib 16 | 17 | # Compiled Static libraries 18 | *.lai 19 | *.la 20 | *.a 21 | 22 | # Windows: 23 | Thumbs.db 24 | ehthumbs.db 25 | Desktop.ini 26 | 27 | # Python: 28 | *.py[cod] 29 | *.so 30 | *.egg 31 | *.egg-info 32 | 33 | # Compiled MATLAB 34 | *.mex* 35 | 36 | # IPython notebook checkpoints 37 | .ipynb_checkpoints 38 | 39 | # Editor temporaries 40 | *.swp 41 | *~ 42 | 43 | # Sublime Text settings 44 | *.sublime-workspace 45 | *.sublime-project 46 | 47 | # Eclipse Project settings 48 | *.*project 49 | .settings 50 | 51 | # QtCreator files 52 | *.user 53 | 54 | # PyCharm files 55 | .idea 56 | 57 | # Visual Studio Code files 58 | .vscode 59 | 60 | # OSX dir files 61 | .DS_Store 62 | 63 | 64 | -------------------------------------------------------------------------------- /CASIA/README.md: -------------------------------------------------------------------------------- 1 | ## Alignment for CASIA-WebFace 2 | 3 | 4 | ``` 5 | python align_CASIA.py CASIA_image_dir aligned_dir 6 | ``` 7 | Errors will be reported to the file `fail-list.txt` 8 | -------------------------------------------------------------------------------- /CASIA/align_CASIA.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | import cv2 4 | import sys 5 | sys.path.insert(0, '../util') 6 | sys.path.insert(0, '../facealign') 7 | 8 | from fileutil import * 9 | from MtcnnPycaffe import MtcnnDetector, draw_and_show 10 | from alignment import FaceAlignVisitor, align_to_96x112 11 | from logfile import * 12 | 13 | 14 | def align_CASIA(src_dir, dst_dir): 15 | log_open('fail-list.txt') 16 | detector = MtcnnDetector(minsize=36) 17 | visitor = FaceAlignVisitor(src_dir,dst_dir,detector, skip_exist = False) 18 | file_walker(src_dir,visitor) 19 | log_close() 20 | 21 | if __name__=='__main__': 22 | if len(sys.argv) < 3: 23 | print('CASIA_image_dir aligned_dir ') 24 | exit() 25 | # 26 | src_dir = sys.argv[1] 27 | dst_dir = sys.argv[2] 28 | align_CASIA(src_dir, dst_dir) 29 | -------------------------------------------------------------------------------- /LFW/README.md: -------------------------------------------------------------------------------- 1 | ## LFW test 2 | 3 | This repo contains codes for the [LFW](http://vis-www.cs.umass.edu/lfw/) face verification test. 4 | Now , it supports for 5 | - [centerface](https://github.com/ydwen/caffe-face) 6 | - [sphereface](https://github.com/wy1iu/sphereface) 7 | - [AMSoftmax](https://github.com/happynear/AMSoftmax) 8 | - [arcface or insightface](https://github.com/deepinsight/insightface) 9 | - [MobileFaceNet](https://github.com/zuoqing1988/ZQCNN/wiki/Model-Zoo-for-Face-Recognition) 10 | 11 | And you can easily use it to test your own models. 12 | 13 | ## Test steps 14 | 15 | ### 1. Prepare [LFW](http://vis-www.cs.umass.edu/lfw/) dataset 16 | Download lfw data 17 | 18 | ```shell 19 | wget http://vis-www.cs.umass.edu/lfw/lfw.tgz 20 | wget http://vis-www.cs.umass.edu/lfw/pairs.txt 21 | tar zxf ./lfw.tgz lfw 22 | ``` 23 | 24 | Clone [insightface](https://github.com/deepinsight/insightface) to $insightface, do alignment with: 25 | 26 | ```shell 27 | python $insightface/src/align/align_lfw.py --input-dir=lfw --output-dir=lfw-112x112 28 | ``` 29 | 30 | ### [Optional] 31 | Download the pre-aligned to 112x112 LFW dataset 32 | This data is transformed from the dataset provided by [arcface](https://github.com/deepinsight/insightface). I convert it from mxnet to numpy which nolonger requires mxnet. 33 | 34 | [lfw-112x112@BaiduDrive](https://pan.baidu.com/s/1uCOedn21j9ZDcm-7yYuhYA) 35 | 36 | **Notice** If you use this data , replace following `--lfw_data=lfw-112x112` with `--lfw_data=lfw.np` 37 | 38 | ### 2. Prepare models 39 | Download the *`caffe`* version of the model from each project and extract files to the corresponding directory under `models`. 40 | 41 | ### 3. Run test 42 | 43 | ```shell 44 | python run_verify.py --lfw_data=lfw-112x112 --model_name=centerface 45 | ``` 46 | 47 | ### 4. Test custom model 48 | Add some code in `run_verify.py` to setup your model 49 | 50 | ``` 51 | def model_yours(do_mirror): 52 | model_dir = '/path/to/your/model/' 53 | model_proto = model_dir + 'deploy.prototxt' 54 | model_path = model_dir + 'weights.caffemodel' 55 | image_size = (112, 112) 56 | extractor = CaffeExtractor(model_proto, model_path, do_mirror = do_mirror, featLayer='fc5') 57 | return extractor, image_size 58 | 59 | 60 | def model_factory(name, do_mirror): 61 | model_dict = { 62 | 'centerface':model_centerface, 63 | 'sphereface':model_sphereface, 64 | 'AMSoftmax':model_AMSoftmax, 65 | 'arcface':model_arcface, 66 | 'model_yours':model_yours, # add your model 67 | } 68 | model_func = model_dict[name] 69 | return model_func(do_mirror) 70 | ``` 71 | 72 | 73 | Run your test with: 74 | 75 | ```shell 76 | python run_verify.py --lfw_data=lfw-112x112 --model_name=yours 77 | ``` 78 | 79 | By default verification will be done with `cosine` distance measure, to test with `L2` distance, run with 80 | 81 | ```shell 82 | python run_verify.py --lfw_data=lfw-112x112 --model_name=yours --dist_type=L2 83 | ``` 84 | Add to save testing time , the horizontal flip feature is not used, if you want to use it ,run with 85 | 86 | ```shell 87 | python run_verify.py --lfw_data=lfw-112x112 --model_name=yours --dist_type=L2 --do_mirror=True 88 | ``` 89 | 90 | ### 5. Results 91 | This is the result I got with default test configuration (flip not used, cosine distance). 92 | 93 | | model | image size | LFW-tested | Offical | 94 | | :-----------: | :--------: | :------------------: | :--------: | 95 | | centerface | 96x112 | 0.98533+-0.00627 | 0.9928 | 96 | | sphereface | 96x112 | 0.99017+-0.00383 | 0.9930 | 97 | | AMSoftmax | 96x112 | 0.98950+-0.00422 | 0.9908 | 98 | | MobileFaceNet | 112x112 | 0.99483+-0.00320 | 0.9969 | 99 | | arcface | 112x112 | **0.99567+-0.00382** | **0.9974** | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /LFW/convert_mx2py.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | import pickle 3 | import sys 4 | import cv2 5 | import numpy as np 6 | import mxnet as mx 7 | 8 | binf = open('./lfw.bin', 'rb') 9 | bins, issame_list = pickle.load(binf) 10 | #binf = open('lfw.bin', 'rb') 11 | #bins, issame_list = pickle.load(binf, encoding='iso-8859-1') 12 | npairs = len(issame_list) 13 | pos_list = [] 14 | neg_list = [] 15 | 16 | for i in range(npairs): 17 | img1 = mx.image.imdecode(bins[i*2]) 18 | npimg1 = img1.asnumpy() 19 | img2 = mx.image.imdecode(bins[i*2+1]) 20 | npimg2 = img2.asnumpy() 21 | if issame_list[i]: 22 | pos_list.append([npimg1, npimg2]) 23 | else: 24 | neg_list.append([npimg1, npimg2]) 25 | 26 | with open('lfw.np', 'wb') as f: 27 | pickle.dump((pos_list, neg_list), f, protocol=pickle.HIGHEST_PROTOCOL) 28 | 29 | -------------------------------------------------------------------------------- /LFW/models/AMSoftmax/deploy.prototxt: -------------------------------------------------------------------------------- 1 | name: "Face-ResNet" 2 | input: "data" 3 | input_dim: 1 4 | input_dim: 3 5 | input_dim: 112 6 | input_dim: 96 7 | layer { 8 | name: "conv1_1" 9 | type: "Convolution" 10 | bottom: "data" 11 | top: "conv1_1" 12 | param { 13 | lr_mult: 1 14 | decay_mult: 1 15 | } 16 | param { 17 | lr_mult: 2 18 | decay_mult: 0 19 | } 20 | convolution_param { 21 | num_output: 64 22 | kernel_size: 3 23 | stride: 2 24 | pad: 1 25 | weight_filler { 26 | type: "xavier" 27 | } 28 | bias_filler { 29 | type: "constant" 30 | value: 0 31 | } 32 | } 33 | } 34 | layer { 35 | name: "relu1_1" 36 | type: "PReLU" 37 | bottom: "conv1_1" 38 | top: "conv1_1" 39 | } 40 | layer { 41 | name: "conv1_2" 42 | type: "Convolution" 43 | bottom: "conv1_1" 44 | top: "conv1_2" 45 | param { 46 | lr_mult: 1 47 | decay_mult: 1 48 | } 49 | param { 50 | lr_mult: 0 51 | decay_mult: 0 52 | } 53 | convolution_param { 54 | num_output: 64 55 | kernel_size: 3 56 | stride: 1 57 | pad: 1 58 | weight_filler { 59 | type: "gaussian" 60 | std: 0.01 61 | } 62 | bias_filler { 63 | type: "constant" 64 | value: 0 65 | } 66 | } 67 | } 68 | layer { 69 | name: "relu1_2" 70 | type: "PReLU" 71 | bottom: "conv1_2" 72 | top: "conv1_2" 73 | } 74 | layer { 75 | name: "conv1_3" 76 | type: "Convolution" 77 | bottom: "conv1_2" 78 | top: "conv1_3" 79 | param { 80 | lr_mult: 1 81 | decay_mult: 1 82 | } 83 | param { 84 | lr_mult: 0 85 | decay_mult: 0 86 | } 87 | convolution_param { 88 | num_output: 64 89 | kernel_size: 3 90 | stride: 1 91 | pad: 1 92 | weight_filler { 93 | type: "gaussian" 94 | std: 0.01 95 | } 96 | bias_filler { 97 | type: "constant" 98 | value: 0 99 | } 100 | } 101 | } 102 | layer { 103 | name: "relu1_3" 104 | type: "PReLU" 105 | bottom: "conv1_3" 106 | top: "conv1_3" 107 | } 108 | layer { 109 | name: "res1_3" 110 | type: "Eltwise" 111 | bottom: "conv1_1" 112 | bottom: "conv1_3" 113 | top: "res1_3" 114 | eltwise_param { 115 | operation: 1 116 | } 117 | } 118 | layer { 119 | name: "conv2_1" 120 | type: "Convolution" 121 | bottom: "res1_3" 122 | top: "conv2_1" 123 | param { 124 | lr_mult: 1 125 | decay_mult: 1 126 | } 127 | param { 128 | lr_mult: 2 129 | decay_mult: 0 130 | } 131 | convolution_param { 132 | num_output: 128 133 | kernel_size: 3 134 | stride: 2 135 | pad: 1 136 | weight_filler { 137 | type: "xavier" 138 | } 139 | bias_filler { 140 | type: "constant" 141 | value: 0 142 | } 143 | } 144 | } 145 | layer { 146 | name: "relu2_1" 147 | type: "PReLU" 148 | bottom: "conv2_1" 149 | top: "conv2_1" 150 | } 151 | layer { 152 | name: "conv2_2" 153 | type: "Convolution" 154 | bottom: "conv2_1" 155 | top: "conv2_2" 156 | param { 157 | lr_mult: 1 158 | decay_mult: 1 159 | } 160 | param { 161 | lr_mult: 0 162 | decay_mult: 0 163 | } 164 | convolution_param { 165 | num_output: 128 166 | kernel_size: 3 167 | stride: 1 168 | pad: 1 169 | weight_filler { 170 | type: "gaussian" 171 | std: 0.01 172 | } 173 | bias_filler { 174 | type: "constant" 175 | value: 0 176 | } 177 | } 178 | } 179 | layer { 180 | name: "relu2_2" 181 | type: "PReLU" 182 | bottom: "conv2_2" 183 | top: "conv2_2" 184 | } 185 | layer { 186 | name: "conv2_3" 187 | type: "Convolution" 188 | bottom: "conv2_2" 189 | top: "conv2_3" 190 | param { 191 | lr_mult: 1 192 | decay_mult: 1 193 | } 194 | param { 195 | lr_mult: 0 196 | decay_mult: 0 197 | } 198 | convolution_param { 199 | num_output: 128 200 | kernel_size: 3 201 | stride: 1 202 | pad: 1 203 | weight_filler { 204 | type: "gaussian" 205 | std: 0.01 206 | } 207 | bias_filler { 208 | type: "constant" 209 | value: 0 210 | } 211 | } 212 | } 213 | layer { 214 | name: "relu2_3" 215 | type: "PReLU" 216 | bottom: "conv2_3" 217 | top: "conv2_3" 218 | } 219 | layer { 220 | name: "res2_3" 221 | type: "Eltwise" 222 | bottom: "conv2_1" 223 | bottom: "conv2_3" 224 | top: "res2_3" 225 | eltwise_param { 226 | operation: 1 227 | } 228 | } 229 | layer { 230 | name: "conv2_4" 231 | type: "Convolution" 232 | bottom: "res2_3" 233 | top: "conv2_4" 234 | param { 235 | lr_mult: 1 236 | decay_mult: 1 237 | } 238 | param { 239 | lr_mult: 0 240 | decay_mult: 0 241 | } 242 | convolution_param { 243 | num_output: 128 244 | kernel_size: 3 245 | stride: 1 246 | pad: 1 247 | weight_filler { 248 | type: "gaussian" 249 | std: 0.01 250 | } 251 | bias_filler { 252 | type: "constant" 253 | value: 0 254 | } 255 | } 256 | } 257 | layer { 258 | name: "relu2_4" 259 | type: "PReLU" 260 | bottom: "conv2_4" 261 | top: "conv2_4" 262 | } 263 | layer { 264 | name: "conv2_5" 265 | type: "Convolution" 266 | bottom: "conv2_4" 267 | top: "conv2_5" 268 | param { 269 | lr_mult: 1 270 | decay_mult: 1 271 | } 272 | param { 273 | lr_mult: 0 274 | decay_mult: 0 275 | } 276 | convolution_param { 277 | num_output: 128 278 | kernel_size: 3 279 | stride: 1 280 | pad: 1 281 | weight_filler { 282 | type: "gaussian" 283 | std: 0.01 284 | } 285 | bias_filler { 286 | type: "constant" 287 | value: 0 288 | } 289 | } 290 | } 291 | layer { 292 | name: "relu2_5" 293 | type: "PReLU" 294 | bottom: "conv2_5" 295 | top: "conv2_5" 296 | } 297 | layer { 298 | name: "res2_5" 299 | type: "Eltwise" 300 | bottom: "res2_3" 301 | bottom: "conv2_5" 302 | top: "res2_5" 303 | eltwise_param { 304 | operation: 1 305 | } 306 | } 307 | layer { 308 | name: "conv3_1" 309 | type: "Convolution" 310 | bottom: "res2_5" 311 | top: "conv3_1" 312 | param { 313 | lr_mult: 1 314 | decay_mult: 1 315 | } 316 | param { 317 | lr_mult: 2 318 | decay_mult: 0 319 | } 320 | convolution_param { 321 | num_output: 256 322 | kernel_size: 3 323 | stride: 2 324 | pad: 1 325 | weight_filler { 326 | type: "xavier" 327 | } 328 | bias_filler { 329 | type: "constant" 330 | value: 0 331 | } 332 | } 333 | } 334 | layer { 335 | name: "relu3_1" 336 | type: "PReLU" 337 | bottom: "conv3_1" 338 | top: "conv3_1" 339 | } 340 | layer { 341 | name: "conv3_2" 342 | type: "Convolution" 343 | bottom: "conv3_1" 344 | top: "conv3_2" 345 | param { 346 | lr_mult: 1 347 | decay_mult: 1 348 | } 349 | param { 350 | lr_mult: 0 351 | decay_mult: 0 352 | } 353 | convolution_param { 354 | num_output: 256 355 | kernel_size: 3 356 | stride: 1 357 | pad: 1 358 | weight_filler { 359 | type: "gaussian" 360 | std: 0.01 361 | } 362 | bias_filler { 363 | type: "constant" 364 | value: 0 365 | } 366 | } 367 | } 368 | layer { 369 | name: "relu3_2" 370 | type: "PReLU" 371 | bottom: "conv3_2" 372 | top: "conv3_2" 373 | } 374 | layer { 375 | name: "conv3_3" 376 | type: "Convolution" 377 | bottom: "conv3_2" 378 | top: "conv3_3" 379 | param { 380 | lr_mult: 1 381 | decay_mult: 1 382 | } 383 | param { 384 | lr_mult: 0 385 | decay_mult: 0 386 | } 387 | convolution_param { 388 | num_output: 256 389 | kernel_size: 3 390 | stride: 1 391 | pad: 1 392 | weight_filler { 393 | type: "gaussian" 394 | std: 0.01 395 | } 396 | bias_filler { 397 | type: "constant" 398 | value: 0 399 | } 400 | } 401 | } 402 | layer { 403 | name: "relu3_3" 404 | type: "PReLU" 405 | bottom: "conv3_3" 406 | top: "conv3_3" 407 | } 408 | layer { 409 | name: "res3_3" 410 | type: "Eltwise" 411 | bottom: "conv3_1" 412 | bottom: "conv3_3" 413 | top: "res3_3" 414 | eltwise_param { 415 | operation: 1 416 | } 417 | } 418 | layer { 419 | name: "conv3_4" 420 | type: "Convolution" 421 | bottom: "res3_3" 422 | top: "conv3_4" 423 | param { 424 | lr_mult: 1 425 | decay_mult: 1 426 | } 427 | param { 428 | lr_mult: 0 429 | decay_mult: 0 430 | } 431 | convolution_param { 432 | num_output: 256 433 | kernel_size: 3 434 | stride: 1 435 | pad: 1 436 | weight_filler { 437 | type: "gaussian" 438 | std: 0.01 439 | } 440 | bias_filler { 441 | type: "constant" 442 | value: 0 443 | } 444 | } 445 | } 446 | layer { 447 | name: "relu3_4" 448 | type: "PReLU" 449 | bottom: "conv3_4" 450 | top: "conv3_4" 451 | } 452 | layer { 453 | name: "conv3_5" 454 | type: "Convolution" 455 | bottom: "conv3_4" 456 | top: "conv3_5" 457 | param { 458 | lr_mult: 1 459 | decay_mult: 1 460 | } 461 | param { 462 | lr_mult: 0 463 | decay_mult: 0 464 | } 465 | convolution_param { 466 | num_output: 256 467 | kernel_size: 3 468 | stride: 1 469 | pad: 1 470 | weight_filler { 471 | type: "gaussian" 472 | std: 0.01 473 | } 474 | bias_filler { 475 | type: "constant" 476 | value: 0 477 | } 478 | } 479 | } 480 | layer { 481 | name: "relu3_5" 482 | type: "PReLU" 483 | bottom: "conv3_5" 484 | top: "conv3_5" 485 | } 486 | layer { 487 | name: "res3_5" 488 | type: "Eltwise" 489 | bottom: "res3_3" 490 | bottom: "conv3_5" 491 | top: "res3_5" 492 | eltwise_param { 493 | operation: 1 494 | } 495 | } 496 | layer { 497 | name: "conv3_6" 498 | type: "Convolution" 499 | bottom: "res3_5" 500 | top: "conv3_6" 501 | param { 502 | lr_mult: 1 503 | decay_mult: 1 504 | } 505 | param { 506 | lr_mult: 0 507 | decay_mult: 0 508 | } 509 | convolution_param { 510 | num_output: 256 511 | kernel_size: 3 512 | stride: 1 513 | pad: 1 514 | weight_filler { 515 | type: "gaussian" 516 | std: 0.01 517 | } 518 | bias_filler { 519 | type: "constant" 520 | value: 0 521 | } 522 | } 523 | } 524 | layer { 525 | name: "relu3_6" 526 | type: "PReLU" 527 | bottom: "conv3_6" 528 | top: "conv3_6" 529 | } 530 | layer { 531 | name: "conv3_7" 532 | type: "Convolution" 533 | bottom: "conv3_6" 534 | top: "conv3_7" 535 | param { 536 | lr_mult: 1 537 | decay_mult: 1 538 | } 539 | param { 540 | lr_mult: 0 541 | decay_mult: 0 542 | } 543 | convolution_param { 544 | num_output: 256 545 | kernel_size: 3 546 | stride: 1 547 | pad: 1 548 | weight_filler { 549 | type: "gaussian" 550 | std: 0.01 551 | } 552 | bias_filler { 553 | type: "constant" 554 | value: 0 555 | } 556 | } 557 | } 558 | layer { 559 | name: "relu3_7" 560 | type: "PReLU" 561 | bottom: "conv3_7" 562 | top: "conv3_7" 563 | } 564 | layer { 565 | name: "res3_7" 566 | type: "Eltwise" 567 | bottom: "res3_5" 568 | bottom: "conv3_7" 569 | top: "res3_7" 570 | eltwise_param { 571 | operation: 1 572 | } 573 | } 574 | layer { 575 | name: "conv3_8" 576 | type: "Convolution" 577 | bottom: "res3_7" 578 | top: "conv3_8" 579 | param { 580 | lr_mult: 1 581 | decay_mult: 1 582 | } 583 | param { 584 | lr_mult: 0 585 | decay_mult: 0 586 | } 587 | convolution_param { 588 | num_output: 256 589 | kernel_size: 3 590 | stride: 1 591 | pad: 1 592 | weight_filler { 593 | type: "gaussian" 594 | std: 0.01 595 | } 596 | bias_filler { 597 | type: "constant" 598 | value: 0 599 | } 600 | } 601 | } 602 | layer { 603 | name: "relu3_8" 604 | type: "PReLU" 605 | bottom: "conv3_8" 606 | top: "conv3_8" 607 | } 608 | layer { 609 | name: "conv3_9" 610 | type: "Convolution" 611 | bottom: "conv3_8" 612 | top: "conv3_9" 613 | param { 614 | lr_mult: 1 615 | decay_mult: 1 616 | } 617 | param { 618 | lr_mult: 0 619 | decay_mult: 0 620 | } 621 | convolution_param { 622 | num_output: 256 623 | kernel_size: 3 624 | stride: 1 625 | pad: 1 626 | weight_filler { 627 | type: "gaussian" 628 | std: 0.01 629 | } 630 | bias_filler { 631 | type: "constant" 632 | value: 0 633 | } 634 | } 635 | } 636 | layer { 637 | name: "relu3_9" 638 | type: "PReLU" 639 | bottom: "conv3_9" 640 | top: "conv3_9" 641 | } 642 | layer { 643 | name: "res3_9" 644 | type: "Eltwise" 645 | bottom: "res3_7" 646 | bottom: "conv3_9" 647 | top: "res3_9" 648 | eltwise_param { 649 | operation: 1 650 | } 651 | } 652 | layer { 653 | name: "conv4_1" 654 | type: "Convolution" 655 | bottom: "res3_9" 656 | top: "conv4_1" 657 | param { 658 | lr_mult: 1 659 | decay_mult: 1 660 | } 661 | param { 662 | lr_mult: 2 663 | decay_mult: 0 664 | } 665 | convolution_param { 666 | num_output: 512 667 | kernel_size: 3 668 | stride: 2 669 | pad: 1 670 | weight_filler { 671 | type: "xavier" 672 | } 673 | bias_filler { 674 | type: "constant" 675 | value: 0 676 | } 677 | } 678 | } 679 | layer { 680 | name: "relu4_1" 681 | type: "PReLU" 682 | bottom: "conv4_1" 683 | top: "conv4_1" 684 | } 685 | layer { 686 | name: "conv4_2" 687 | type: "Convolution" 688 | bottom: "conv4_1" 689 | top: "conv4_2" 690 | param { 691 | lr_mult: 1 692 | decay_mult: 1 693 | } 694 | param { 695 | lr_mult: 0 696 | decay_mult: 0 697 | } 698 | convolution_param { 699 | num_output: 512 700 | kernel_size: 3 701 | stride: 1 702 | pad: 1 703 | weight_filler { 704 | type: "gaussian" 705 | std: 0.01 706 | } 707 | bias_filler { 708 | type: "constant" 709 | value: 0 710 | } 711 | } 712 | } 713 | layer { 714 | name: "relu4_2" 715 | type: "PReLU" 716 | bottom: "conv4_2" 717 | top: "conv4_2" 718 | } 719 | layer { 720 | name: "conv4_3" 721 | type: "Convolution" 722 | bottom: "conv4_2" 723 | top: "conv4_3" 724 | param { 725 | lr_mult: 1 726 | decay_mult: 1 727 | } 728 | param { 729 | lr_mult: 0 730 | decay_mult: 0 731 | } 732 | convolution_param { 733 | num_output: 512 734 | kernel_size: 3 735 | stride: 1 736 | pad: 1 737 | weight_filler { 738 | type: "gaussian" 739 | std: 0.01 740 | } 741 | bias_filler { 742 | type: "constant" 743 | value: 0 744 | } 745 | } 746 | } 747 | layer { 748 | name: "relu4_3" 749 | type: "PReLU" 750 | bottom: "conv4_3" 751 | top: "conv4_3" 752 | } 753 | layer { 754 | name: "res4_3" 755 | type: "Eltwise" 756 | bottom: "conv4_1" 757 | bottom: "conv4_3" 758 | top: "res4_3" 759 | eltwise_param { 760 | operation: 1 761 | } 762 | } 763 | layer { 764 | name: "fc5" 765 | type: "InnerProduct" 766 | bottom: "res4_3" 767 | top: "fc5" 768 | param { 769 | lr_mult: 1 770 | decay_mult: 1 771 | } 772 | param { 773 | lr_mult: 2 774 | decay_mult: 0 775 | } 776 | inner_product_param { 777 | num_output: 512 778 | weight_filler { 779 | type: "xavier" 780 | } 781 | bias_filler { 782 | type: "constant" 783 | value: 0 784 | } 785 | } 786 | } 787 | 788 | -------------------------------------------------------------------------------- /LFW/models/AMSoftmax/face_deploy_mirror_normalize.prototxt: -------------------------------------------------------------------------------- 1 | input: "data" 2 | input_dim: 1 3 | input_dim: 3 4 | input_dim: 112 5 | input_dim: 96 6 | layer { 7 | name: "flip_data" 8 | type: "Flip" 9 | bottom: "data" 10 | top: "flip_data" 11 | } 12 | layer { 13 | name: "concat_data" 14 | type: "Concat" 15 | bottom: "data" 16 | bottom: "flip_data" 17 | top: "concat_data" 18 | concat_param{ 19 | axis: 0 20 | } 21 | } 22 | layer { 23 | name: "conv1_1" 24 | type: "Convolution" 25 | bottom: "concat_data" 26 | top: "conv1_1" 27 | param { 28 | lr_mult: 1 29 | decay_mult: 1 30 | } 31 | param { 32 | lr_mult: 2 33 | decay_mult: 0 34 | } 35 | convolution_param { 36 | num_output: 64 37 | kernel_size: 3 38 | stride: 2 39 | pad: 1 40 | weight_filler { 41 | type: "xavier" 42 | } 43 | bias_filler { 44 | type: "constant" 45 | value: 0 46 | } 47 | } 48 | } 49 | layer { 50 | name: "relu1_1" 51 | type: "PReLU" 52 | bottom: "conv1_1" 53 | top: "conv1_1" 54 | } 55 | layer { 56 | name: "conv1_2" 57 | type: "Convolution" 58 | bottom: "conv1_1" 59 | top: "conv1_2" 60 | param { 61 | lr_mult: 1 62 | decay_mult: 1 63 | } 64 | param { 65 | lr_mult: 0 66 | decay_mult: 0 67 | } 68 | convolution_param { 69 | num_output: 64 70 | kernel_size: 3 71 | stride: 1 72 | pad: 1 73 | weight_filler { 74 | type: "gaussian" 75 | std: 0.01 76 | } 77 | bias_filler { 78 | type: "constant" 79 | value: 0 80 | } 81 | } 82 | } 83 | layer { 84 | name: "relu1_2" 85 | type: "PReLU" 86 | bottom: "conv1_2" 87 | top: "conv1_2" 88 | } 89 | layer { 90 | name: "conv1_3" 91 | type: "Convolution" 92 | bottom: "conv1_2" 93 | top: "conv1_3" 94 | param { 95 | lr_mult: 1 96 | decay_mult: 1 97 | } 98 | param { 99 | lr_mult: 0 100 | decay_mult: 0 101 | } 102 | convolution_param { 103 | num_output: 64 104 | kernel_size: 3 105 | stride: 1 106 | pad: 1 107 | weight_filler { 108 | type: "gaussian" 109 | std: 0.01 110 | } 111 | bias_filler { 112 | type: "constant" 113 | value: 0 114 | } 115 | } 116 | } 117 | layer { 118 | name: "relu1_3" 119 | type: "PReLU" 120 | bottom: "conv1_3" 121 | top: "conv1_3" 122 | } 123 | layer { 124 | name: "res1_3" 125 | type: "Eltwise" 126 | bottom: "conv1_1" 127 | bottom: "conv1_3" 128 | top: "res1_3" 129 | eltwise_param { 130 | operation: 1 131 | } 132 | } 133 | layer { 134 | name: "conv2_1" 135 | type: "Convolution" 136 | bottom: "res1_3" 137 | top: "conv2_1" 138 | param { 139 | lr_mult: 1 140 | decay_mult: 1 141 | } 142 | param { 143 | lr_mult: 2 144 | decay_mult: 0 145 | } 146 | convolution_param { 147 | num_output: 128 148 | kernel_size: 3 149 | stride: 2 150 | pad: 1 151 | weight_filler { 152 | type: "xavier" 153 | } 154 | bias_filler { 155 | type: "constant" 156 | value: 0 157 | } 158 | } 159 | } 160 | layer { 161 | name: "relu2_1" 162 | type: "PReLU" 163 | bottom: "conv2_1" 164 | top: "conv2_1" 165 | } 166 | layer { 167 | name: "conv2_2" 168 | type: "Convolution" 169 | bottom: "conv2_1" 170 | top: "conv2_2" 171 | param { 172 | lr_mult: 1 173 | decay_mult: 1 174 | } 175 | param { 176 | lr_mult: 0 177 | decay_mult: 0 178 | } 179 | convolution_param { 180 | num_output: 128 181 | kernel_size: 3 182 | stride: 1 183 | pad: 1 184 | weight_filler { 185 | type: "gaussian" 186 | std: 0.01 187 | } 188 | bias_filler { 189 | type: "constant" 190 | value: 0 191 | } 192 | } 193 | } 194 | layer { 195 | name: "relu2_2" 196 | type: "PReLU" 197 | bottom: "conv2_2" 198 | top: "conv2_2" 199 | } 200 | layer { 201 | name: "conv2_3" 202 | type: "Convolution" 203 | bottom: "conv2_2" 204 | top: "conv2_3" 205 | param { 206 | lr_mult: 1 207 | decay_mult: 1 208 | } 209 | param { 210 | lr_mult: 0 211 | decay_mult: 0 212 | } 213 | convolution_param { 214 | num_output: 128 215 | kernel_size: 3 216 | stride: 1 217 | pad: 1 218 | weight_filler { 219 | type: "gaussian" 220 | std: 0.01 221 | } 222 | bias_filler { 223 | type: "constant" 224 | value: 0 225 | } 226 | } 227 | } 228 | layer { 229 | name: "relu2_3" 230 | type: "PReLU" 231 | bottom: "conv2_3" 232 | top: "conv2_3" 233 | } 234 | layer { 235 | name: "res2_3" 236 | type: "Eltwise" 237 | bottom: "conv2_1" 238 | bottom: "conv2_3" 239 | top: "res2_3" 240 | eltwise_param { 241 | operation: 1 242 | } 243 | } 244 | layer { 245 | name: "conv2_4" 246 | type: "Convolution" 247 | bottom: "res2_3" 248 | top: "conv2_4" 249 | param { 250 | lr_mult: 1 251 | decay_mult: 1 252 | } 253 | param { 254 | lr_mult: 0 255 | decay_mult: 0 256 | } 257 | convolution_param { 258 | num_output: 128 259 | kernel_size: 3 260 | stride: 1 261 | pad: 1 262 | weight_filler { 263 | type: "gaussian" 264 | std: 0.01 265 | } 266 | bias_filler { 267 | type: "constant" 268 | value: 0 269 | } 270 | } 271 | } 272 | layer { 273 | name: "relu2_4" 274 | type: "PReLU" 275 | bottom: "conv2_4" 276 | top: "conv2_4" 277 | } 278 | layer { 279 | name: "conv2_5" 280 | type: "Convolution" 281 | bottom: "conv2_4" 282 | top: "conv2_5" 283 | param { 284 | lr_mult: 1 285 | decay_mult: 1 286 | } 287 | param { 288 | lr_mult: 0 289 | decay_mult: 0 290 | } 291 | convolution_param { 292 | num_output: 128 293 | kernel_size: 3 294 | stride: 1 295 | pad: 1 296 | weight_filler { 297 | type: "gaussian" 298 | std: 0.01 299 | } 300 | bias_filler { 301 | type: "constant" 302 | value: 0 303 | } 304 | } 305 | } 306 | layer { 307 | name: "relu2_5" 308 | type: "PReLU" 309 | bottom: "conv2_5" 310 | top: "conv2_5" 311 | } 312 | layer { 313 | name: "res2_5" 314 | type: "Eltwise" 315 | bottom: "res2_3" 316 | bottom: "conv2_5" 317 | top: "res2_5" 318 | eltwise_param { 319 | operation: 1 320 | } 321 | } 322 | layer { 323 | name: "conv3_1" 324 | type: "Convolution" 325 | bottom: "res2_5" 326 | top: "conv3_1" 327 | param { 328 | lr_mult: 1 329 | decay_mult: 1 330 | } 331 | param { 332 | lr_mult: 2 333 | decay_mult: 0 334 | } 335 | convolution_param { 336 | num_output: 256 337 | kernel_size: 3 338 | stride: 2 339 | pad: 1 340 | weight_filler { 341 | type: "xavier" 342 | } 343 | bias_filler { 344 | type: "constant" 345 | value: 0 346 | } 347 | } 348 | } 349 | layer { 350 | name: "relu3_1" 351 | type: "PReLU" 352 | bottom: "conv3_1" 353 | top: "conv3_1" 354 | } 355 | layer { 356 | name: "conv3_2" 357 | type: "Convolution" 358 | bottom: "conv3_1" 359 | top: "conv3_2" 360 | param { 361 | lr_mult: 1 362 | decay_mult: 1 363 | } 364 | param { 365 | lr_mult: 0 366 | decay_mult: 0 367 | } 368 | convolution_param { 369 | num_output: 256 370 | kernel_size: 3 371 | stride: 1 372 | pad: 1 373 | weight_filler { 374 | type: "gaussian" 375 | std: 0.01 376 | } 377 | bias_filler { 378 | type: "constant" 379 | value: 0 380 | } 381 | } 382 | } 383 | layer { 384 | name: "relu3_2" 385 | type: "PReLU" 386 | bottom: "conv3_2" 387 | top: "conv3_2" 388 | } 389 | layer { 390 | name: "conv3_3" 391 | type: "Convolution" 392 | bottom: "conv3_2" 393 | top: "conv3_3" 394 | param { 395 | lr_mult: 1 396 | decay_mult: 1 397 | } 398 | param { 399 | lr_mult: 0 400 | decay_mult: 0 401 | } 402 | convolution_param { 403 | num_output: 256 404 | kernel_size: 3 405 | stride: 1 406 | pad: 1 407 | weight_filler { 408 | type: "gaussian" 409 | std: 0.01 410 | } 411 | bias_filler { 412 | type: "constant" 413 | value: 0 414 | } 415 | } 416 | } 417 | layer { 418 | name: "relu3_3" 419 | type: "PReLU" 420 | bottom: "conv3_3" 421 | top: "conv3_3" 422 | } 423 | layer { 424 | name: "res3_3" 425 | type: "Eltwise" 426 | bottom: "conv3_1" 427 | bottom: "conv3_3" 428 | top: "res3_3" 429 | eltwise_param { 430 | operation: 1 431 | } 432 | } 433 | layer { 434 | name: "conv3_4" 435 | type: "Convolution" 436 | bottom: "res3_3" 437 | top: "conv3_4" 438 | param { 439 | lr_mult: 1 440 | decay_mult: 1 441 | } 442 | param { 443 | lr_mult: 0 444 | decay_mult: 0 445 | } 446 | convolution_param { 447 | num_output: 256 448 | kernel_size: 3 449 | stride: 1 450 | pad: 1 451 | weight_filler { 452 | type: "gaussian" 453 | std: 0.01 454 | } 455 | bias_filler { 456 | type: "constant" 457 | value: 0 458 | } 459 | } 460 | } 461 | layer { 462 | name: "relu3_4" 463 | type: "PReLU" 464 | bottom: "conv3_4" 465 | top: "conv3_4" 466 | } 467 | layer { 468 | name: "conv3_5" 469 | type: "Convolution" 470 | bottom: "conv3_4" 471 | top: "conv3_5" 472 | param { 473 | lr_mult: 1 474 | decay_mult: 1 475 | } 476 | param { 477 | lr_mult: 0 478 | decay_mult: 0 479 | } 480 | convolution_param { 481 | num_output: 256 482 | kernel_size: 3 483 | stride: 1 484 | pad: 1 485 | weight_filler { 486 | type: "gaussian" 487 | std: 0.01 488 | } 489 | bias_filler { 490 | type: "constant" 491 | value: 0 492 | } 493 | } 494 | } 495 | layer { 496 | name: "relu3_5" 497 | type: "PReLU" 498 | bottom: "conv3_5" 499 | top: "conv3_5" 500 | } 501 | layer { 502 | name: "res3_5" 503 | type: "Eltwise" 504 | bottom: "res3_3" 505 | bottom: "conv3_5" 506 | top: "res3_5" 507 | eltwise_param { 508 | operation: 1 509 | } 510 | } 511 | layer { 512 | name: "conv3_6" 513 | type: "Convolution" 514 | bottom: "res3_5" 515 | top: "conv3_6" 516 | param { 517 | lr_mult: 1 518 | decay_mult: 1 519 | } 520 | param { 521 | lr_mult: 0 522 | decay_mult: 0 523 | } 524 | convolution_param { 525 | num_output: 256 526 | kernel_size: 3 527 | stride: 1 528 | pad: 1 529 | weight_filler { 530 | type: "gaussian" 531 | std: 0.01 532 | } 533 | bias_filler { 534 | type: "constant" 535 | value: 0 536 | } 537 | } 538 | } 539 | layer { 540 | name: "relu3_6" 541 | type: "PReLU" 542 | bottom: "conv3_6" 543 | top: "conv3_6" 544 | } 545 | layer { 546 | name: "conv3_7" 547 | type: "Convolution" 548 | bottom: "conv3_6" 549 | top: "conv3_7" 550 | param { 551 | lr_mult: 1 552 | decay_mult: 1 553 | } 554 | param { 555 | lr_mult: 0 556 | decay_mult: 0 557 | } 558 | convolution_param { 559 | num_output: 256 560 | kernel_size: 3 561 | stride: 1 562 | pad: 1 563 | weight_filler { 564 | type: "gaussian" 565 | std: 0.01 566 | } 567 | bias_filler { 568 | type: "constant" 569 | value: 0 570 | } 571 | } 572 | } 573 | layer { 574 | name: "relu3_7" 575 | type: "PReLU" 576 | bottom: "conv3_7" 577 | top: "conv3_7" 578 | } 579 | layer { 580 | name: "res3_7" 581 | type: "Eltwise" 582 | bottom: "res3_5" 583 | bottom: "conv3_7" 584 | top: "res3_7" 585 | eltwise_param { 586 | operation: 1 587 | } 588 | } 589 | layer { 590 | name: "conv3_8" 591 | type: "Convolution" 592 | bottom: "res3_7" 593 | top: "conv3_8" 594 | param { 595 | lr_mult: 1 596 | decay_mult: 1 597 | } 598 | param { 599 | lr_mult: 0 600 | decay_mult: 0 601 | } 602 | convolution_param { 603 | num_output: 256 604 | kernel_size: 3 605 | stride: 1 606 | pad: 1 607 | weight_filler { 608 | type: "gaussian" 609 | std: 0.01 610 | } 611 | bias_filler { 612 | type: "constant" 613 | value: 0 614 | } 615 | } 616 | } 617 | layer { 618 | name: "relu3_8" 619 | type: "PReLU" 620 | bottom: "conv3_8" 621 | top: "conv3_8" 622 | } 623 | layer { 624 | name: "conv3_9" 625 | type: "Convolution" 626 | bottom: "conv3_8" 627 | top: "conv3_9" 628 | param { 629 | lr_mult: 1 630 | decay_mult: 1 631 | } 632 | param { 633 | lr_mult: 0 634 | decay_mult: 0 635 | } 636 | convolution_param { 637 | num_output: 256 638 | kernel_size: 3 639 | stride: 1 640 | pad: 1 641 | weight_filler { 642 | type: "gaussian" 643 | std: 0.01 644 | } 645 | bias_filler { 646 | type: "constant" 647 | value: 0 648 | } 649 | } 650 | } 651 | layer { 652 | name: "relu3_9" 653 | type: "PReLU" 654 | bottom: "conv3_9" 655 | top: "conv3_9" 656 | } 657 | layer { 658 | name: "res3_9" 659 | type: "Eltwise" 660 | bottom: "res3_7" 661 | bottom: "conv3_9" 662 | top: "res3_9" 663 | eltwise_param { 664 | operation: 1 665 | } 666 | } 667 | layer { 668 | name: "conv4_1" 669 | type: "Convolution" 670 | bottom: "res3_9" 671 | top: "conv4_1" 672 | param { 673 | lr_mult: 1 674 | decay_mult: 1 675 | } 676 | param { 677 | lr_mult: 2 678 | decay_mult: 0 679 | } 680 | convolution_param { 681 | num_output: 512 682 | kernel_size: 3 683 | stride: 2 684 | pad: 1 685 | weight_filler { 686 | type: "xavier" 687 | } 688 | bias_filler { 689 | type: "constant" 690 | value: 0 691 | } 692 | } 693 | } 694 | layer { 695 | name: "relu4_1" 696 | type: "PReLU" 697 | bottom: "conv4_1" 698 | top: "conv4_1" 699 | } 700 | layer { 701 | name: "conv4_2" 702 | type: "Convolution" 703 | bottom: "conv4_1" 704 | top: "conv4_2" 705 | param { 706 | lr_mult: 1 707 | decay_mult: 1 708 | } 709 | param { 710 | lr_mult: 0 711 | decay_mult: 0 712 | } 713 | convolution_param { 714 | num_output: 512 715 | kernel_size: 3 716 | stride: 1 717 | pad: 1 718 | weight_filler { 719 | type: "gaussian" 720 | std: 0.01 721 | } 722 | bias_filler { 723 | type: "constant" 724 | value: 0 725 | } 726 | } 727 | } 728 | layer { 729 | name: "relu4_2" 730 | type: "PReLU" 731 | bottom: "conv4_2" 732 | top: "conv4_2" 733 | } 734 | layer { 735 | name: "conv4_3" 736 | type: "Convolution" 737 | bottom: "conv4_2" 738 | top: "conv4_3" 739 | param { 740 | lr_mult: 1 741 | decay_mult: 1 742 | } 743 | param { 744 | lr_mult: 0 745 | decay_mult: 0 746 | } 747 | convolution_param { 748 | num_output: 512 749 | kernel_size: 3 750 | stride: 1 751 | pad: 1 752 | weight_filler { 753 | type: "gaussian" 754 | std: 0.01 755 | } 756 | bias_filler { 757 | type: "constant" 758 | value: 0 759 | } 760 | } 761 | } 762 | layer { 763 | name: "relu4_3" 764 | type: "PReLU" 765 | bottom: "conv4_3" 766 | top: "conv4_3" 767 | } 768 | layer { 769 | name: "res4_3" 770 | type: "Eltwise" 771 | bottom: "conv4_1" 772 | bottom: "conv4_3" 773 | top: "res4_3" 774 | eltwise_param { 775 | operation: 1 776 | } 777 | } 778 | layer { 779 | name: "fc5" 780 | type: "InnerProduct" 781 | bottom: "res4_3" 782 | top: "fc5" 783 | param { 784 | lr_mult: 1 785 | decay_mult: 1 786 | } 787 | param { 788 | lr_mult: 2 789 | decay_mult: 0 790 | } 791 | inner_product_param { 792 | num_output: 512 793 | weight_filler { 794 | type: "xavier" 795 | } 796 | bias_filler { 797 | type: "constant" 798 | value: 0 799 | } 800 | } 801 | } 802 | layer { 803 | name: "slice_fc5" 804 | type: "Slice" 805 | bottom: "fc5" 806 | top: "fc5_orig" 807 | top: "fc5_mirror" 808 | slice_param { 809 | axis: 0 810 | } 811 | } 812 | layer { 813 | name: "eltmax_fc5" 814 | type: "Eltwise" 815 | bottom: "fc5_orig" 816 | bottom: "fc5_mirror" 817 | top: "eltmax_fc5" 818 | eltwise_param { 819 | operation: SUM 820 | } 821 | } 822 | layer { 823 | name: "normalize1" 824 | type: "Normalize" 825 | bottom: "eltmax_fc5" 826 | top: "norm1" 827 | normalize_param { 828 | normalize_type: "L2" 829 | } 830 | } -------------------------------------------------------------------------------- /LFW/models/AMSoftmax/face_train_test.prototxt: -------------------------------------------------------------------------------- 1 | name: "Face-ResNet" 2 | layer { 3 | name: "data" 4 | type: "ImageData" 5 | top: "data" 6 | top: "label" 7 | include { 8 | phase: TRAIN 9 | } 10 | transform_param { 11 | mean_value: 128 12 | scale: 0.0078125 13 | mirror: true 14 | } 15 | image_data_param { 16 | source: "C:/datasets/CASIA-maxpy-clean-aligned-96/list.txt" 17 | root_folder: "C:/datasets/CASIA-maxpy-clean-aligned-96/" 18 | batch_size: 256 19 | shuffle: true 20 | } 21 | } 22 | layer { 23 | name: "data" 24 | type: "ImageData" 25 | top: "data" 26 | top: "label" 27 | include { 28 | phase: TEST 29 | } 30 | transform_param { 31 | mean_value: 128 32 | scale: 0.0078125 33 | mirror: true 34 | } 35 | image_data_param { 36 | source: "C:/datasets/CASIA-maxpy-clean-aligned-96/val.txt" 37 | root_folder: "C:/datasets/CASIA-maxpy-clean-aligned-96/" 38 | batch_size: 32 39 | shuffle: true 40 | } 41 | } 42 | layer { 43 | name: "conv1_1" 44 | type: "Convolution" 45 | bottom: "data" 46 | top: "conv1_1" 47 | param { 48 | lr_mult: 1 49 | decay_mult: 1 50 | } 51 | param { 52 | lr_mult: 2 53 | decay_mult: 0 54 | } 55 | convolution_param { 56 | num_output: 64 57 | kernel_size: 3 58 | stride: 2 59 | pad: 1 60 | weight_filler { 61 | type: "xavier" 62 | } 63 | bias_filler { 64 | type: "constant" 65 | value: 0 66 | } 67 | } 68 | } 69 | layer { 70 | name: "relu1_1" 71 | type: "PReLU" 72 | bottom: "conv1_1" 73 | top: "conv1_1" 74 | } 75 | layer { 76 | name: "conv1_2" 77 | type: "Convolution" 78 | bottom: "conv1_1" 79 | top: "conv1_2" 80 | param { 81 | lr_mult: 1 82 | decay_mult: 1 83 | } 84 | param { 85 | lr_mult: 0 86 | decay_mult: 0 87 | } 88 | convolution_param { 89 | num_output: 64 90 | kernel_size: 3 91 | stride: 1 92 | pad: 1 93 | weight_filler { 94 | type: "gaussian" 95 | std: 0.01 96 | } 97 | bias_filler { 98 | type: "constant" 99 | value: 0 100 | } 101 | } 102 | } 103 | layer { 104 | name: "relu1_2" 105 | type: "PReLU" 106 | bottom: "conv1_2" 107 | top: "conv1_2" 108 | } 109 | layer { 110 | name: "conv1_3" 111 | type: "Convolution" 112 | bottom: "conv1_2" 113 | top: "conv1_3" 114 | param { 115 | lr_mult: 1 116 | decay_mult: 1 117 | } 118 | param { 119 | lr_mult: 0 120 | decay_mult: 0 121 | } 122 | convolution_param { 123 | num_output: 64 124 | kernel_size: 3 125 | stride: 1 126 | pad: 1 127 | weight_filler { 128 | type: "gaussian" 129 | std: 0.01 130 | } 131 | bias_filler { 132 | type: "constant" 133 | value: 0 134 | } 135 | } 136 | } 137 | layer { 138 | name: "relu1_3" 139 | type: "PReLU" 140 | bottom: "conv1_3" 141 | top: "conv1_3" 142 | } 143 | layer { 144 | name: "res1_3" 145 | type: "Eltwise" 146 | bottom: "conv1_1" 147 | bottom: "conv1_3" 148 | top: "res1_3" 149 | eltwise_param { 150 | operation: 1 151 | } 152 | } 153 | layer { 154 | name: "conv2_1" 155 | type: "Convolution" 156 | bottom: "res1_3" 157 | top: "conv2_1" 158 | param { 159 | lr_mult: 1 160 | decay_mult: 1 161 | } 162 | param { 163 | lr_mult: 2 164 | decay_mult: 0 165 | } 166 | convolution_param { 167 | num_output: 128 168 | kernel_size: 3 169 | stride: 2 170 | pad: 1 171 | weight_filler { 172 | type: "xavier" 173 | } 174 | bias_filler { 175 | type: "constant" 176 | value: 0 177 | } 178 | } 179 | } 180 | layer { 181 | name: "relu2_1" 182 | type: "PReLU" 183 | bottom: "conv2_1" 184 | top: "conv2_1" 185 | } 186 | layer { 187 | name: "conv2_2" 188 | type: "Convolution" 189 | bottom: "conv2_1" 190 | top: "conv2_2" 191 | param { 192 | lr_mult: 1 193 | decay_mult: 1 194 | } 195 | param { 196 | lr_mult: 0 197 | decay_mult: 0 198 | } 199 | convolution_param { 200 | num_output: 128 201 | kernel_size: 3 202 | stride: 1 203 | pad: 1 204 | weight_filler { 205 | type: "gaussian" 206 | std: 0.01 207 | } 208 | bias_filler { 209 | type: "constant" 210 | value: 0 211 | } 212 | } 213 | } 214 | layer { 215 | name: "relu2_2" 216 | type: "PReLU" 217 | bottom: "conv2_2" 218 | top: "conv2_2" 219 | } 220 | layer { 221 | name: "conv2_3" 222 | type: "Convolution" 223 | bottom: "conv2_2" 224 | top: "conv2_3" 225 | param { 226 | lr_mult: 1 227 | decay_mult: 1 228 | } 229 | param { 230 | lr_mult: 0 231 | decay_mult: 0 232 | } 233 | convolution_param { 234 | num_output: 128 235 | kernel_size: 3 236 | stride: 1 237 | pad: 1 238 | weight_filler { 239 | type: "gaussian" 240 | std: 0.01 241 | } 242 | bias_filler { 243 | type: "constant" 244 | value: 0 245 | } 246 | } 247 | } 248 | layer { 249 | name: "relu2_3" 250 | type: "PReLU" 251 | bottom: "conv2_3" 252 | top: "conv2_3" 253 | } 254 | layer { 255 | name: "res2_3" 256 | type: "Eltwise" 257 | bottom: "conv2_1" 258 | bottom: "conv2_3" 259 | top: "res2_3" 260 | eltwise_param { 261 | operation: 1 262 | } 263 | } 264 | layer { 265 | name: "conv2_4" 266 | type: "Convolution" 267 | bottom: "res2_3" 268 | top: "conv2_4" 269 | param { 270 | lr_mult: 1 271 | decay_mult: 1 272 | } 273 | param { 274 | lr_mult: 0 275 | decay_mult: 0 276 | } 277 | convolution_param { 278 | num_output: 128 279 | kernel_size: 3 280 | stride: 1 281 | pad: 1 282 | weight_filler { 283 | type: "gaussian" 284 | std: 0.01 285 | } 286 | bias_filler { 287 | type: "constant" 288 | value: 0 289 | } 290 | } 291 | } 292 | layer { 293 | name: "relu2_4" 294 | type: "PReLU" 295 | bottom: "conv2_4" 296 | top: "conv2_4" 297 | } 298 | layer { 299 | name: "conv2_5" 300 | type: "Convolution" 301 | bottom: "conv2_4" 302 | top: "conv2_5" 303 | param { 304 | lr_mult: 1 305 | decay_mult: 1 306 | } 307 | param { 308 | lr_mult: 0 309 | decay_mult: 0 310 | } 311 | convolution_param { 312 | num_output: 128 313 | kernel_size: 3 314 | stride: 1 315 | pad: 1 316 | weight_filler { 317 | type: "gaussian" 318 | std: 0.01 319 | } 320 | bias_filler { 321 | type: "constant" 322 | value: 0 323 | } 324 | } 325 | } 326 | layer { 327 | name: "relu2_5" 328 | type: "PReLU" 329 | bottom: "conv2_5" 330 | top: "conv2_5" 331 | } 332 | layer { 333 | name: "res2_5" 334 | type: "Eltwise" 335 | bottom: "res2_3" 336 | bottom: "conv2_5" 337 | top: "res2_5" 338 | eltwise_param { 339 | operation: 1 340 | } 341 | } 342 | layer { 343 | name: "conv3_1" 344 | type: "Convolution" 345 | bottom: "res2_5" 346 | top: "conv3_1" 347 | param { 348 | lr_mult: 1 349 | decay_mult: 1 350 | } 351 | param { 352 | lr_mult: 2 353 | decay_mult: 0 354 | } 355 | convolution_param { 356 | num_output: 256 357 | kernel_size: 3 358 | stride: 2 359 | pad: 1 360 | weight_filler { 361 | type: "xavier" 362 | } 363 | bias_filler { 364 | type: "constant" 365 | value: 0 366 | } 367 | } 368 | } 369 | layer { 370 | name: "relu3_1" 371 | type: "PReLU" 372 | bottom: "conv3_1" 373 | top: "conv3_1" 374 | } 375 | layer { 376 | name: "conv3_2" 377 | type: "Convolution" 378 | bottom: "conv3_1" 379 | top: "conv3_2" 380 | param { 381 | lr_mult: 1 382 | decay_mult: 1 383 | } 384 | param { 385 | lr_mult: 0 386 | decay_mult: 0 387 | } 388 | convolution_param { 389 | num_output: 256 390 | kernel_size: 3 391 | stride: 1 392 | pad: 1 393 | weight_filler { 394 | type: "gaussian" 395 | std: 0.01 396 | } 397 | bias_filler { 398 | type: "constant" 399 | value: 0 400 | } 401 | } 402 | } 403 | layer { 404 | name: "relu3_2" 405 | type: "PReLU" 406 | bottom: "conv3_2" 407 | top: "conv3_2" 408 | } 409 | layer { 410 | name: "conv3_3" 411 | type: "Convolution" 412 | bottom: "conv3_2" 413 | top: "conv3_3" 414 | param { 415 | lr_mult: 1 416 | decay_mult: 1 417 | } 418 | param { 419 | lr_mult: 0 420 | decay_mult: 0 421 | } 422 | convolution_param { 423 | num_output: 256 424 | kernel_size: 3 425 | stride: 1 426 | pad: 1 427 | weight_filler { 428 | type: "gaussian" 429 | std: 0.01 430 | } 431 | bias_filler { 432 | type: "constant" 433 | value: 0 434 | } 435 | } 436 | } 437 | layer { 438 | name: "relu3_3" 439 | type: "PReLU" 440 | bottom: "conv3_3" 441 | top: "conv3_3" 442 | } 443 | layer { 444 | name: "res3_3" 445 | type: "Eltwise" 446 | bottom: "conv3_1" 447 | bottom: "conv3_3" 448 | top: "res3_3" 449 | eltwise_param { 450 | operation: 1 451 | } 452 | } 453 | layer { 454 | name: "conv3_4" 455 | type: "Convolution" 456 | bottom: "res3_3" 457 | top: "conv3_4" 458 | param { 459 | lr_mult: 1 460 | decay_mult: 1 461 | } 462 | param { 463 | lr_mult: 0 464 | decay_mult: 0 465 | } 466 | convolution_param { 467 | num_output: 256 468 | kernel_size: 3 469 | stride: 1 470 | pad: 1 471 | weight_filler { 472 | type: "gaussian" 473 | std: 0.01 474 | } 475 | bias_filler { 476 | type: "constant" 477 | value: 0 478 | } 479 | } 480 | } 481 | layer { 482 | name: "relu3_4" 483 | type: "PReLU" 484 | bottom: "conv3_4" 485 | top: "conv3_4" 486 | } 487 | layer { 488 | name: "conv3_5" 489 | type: "Convolution" 490 | bottom: "conv3_4" 491 | top: "conv3_5" 492 | param { 493 | lr_mult: 1 494 | decay_mult: 1 495 | } 496 | param { 497 | lr_mult: 0 498 | decay_mult: 0 499 | } 500 | convolution_param { 501 | num_output: 256 502 | kernel_size: 3 503 | stride: 1 504 | pad: 1 505 | weight_filler { 506 | type: "gaussian" 507 | std: 0.01 508 | } 509 | bias_filler { 510 | type: "constant" 511 | value: 0 512 | } 513 | } 514 | } 515 | layer { 516 | name: "relu3_5" 517 | type: "PReLU" 518 | bottom: "conv3_5" 519 | top: "conv3_5" 520 | } 521 | layer { 522 | name: "res3_5" 523 | type: "Eltwise" 524 | bottom: "res3_3" 525 | bottom: "conv3_5" 526 | top: "res3_5" 527 | eltwise_param { 528 | operation: 1 529 | } 530 | } 531 | layer { 532 | name: "conv3_6" 533 | type: "Convolution" 534 | bottom: "res3_5" 535 | top: "conv3_6" 536 | param { 537 | lr_mult: 1 538 | decay_mult: 1 539 | } 540 | param { 541 | lr_mult: 0 542 | decay_mult: 0 543 | } 544 | convolution_param { 545 | num_output: 256 546 | kernel_size: 3 547 | stride: 1 548 | pad: 1 549 | weight_filler { 550 | type: "gaussian" 551 | std: 0.01 552 | } 553 | bias_filler { 554 | type: "constant" 555 | value: 0 556 | } 557 | } 558 | } 559 | layer { 560 | name: "relu3_6" 561 | type: "PReLU" 562 | bottom: "conv3_6" 563 | top: "conv3_6" 564 | } 565 | layer { 566 | name: "conv3_7" 567 | type: "Convolution" 568 | bottom: "conv3_6" 569 | top: "conv3_7" 570 | param { 571 | lr_mult: 1 572 | decay_mult: 1 573 | } 574 | param { 575 | lr_mult: 0 576 | decay_mult: 0 577 | } 578 | convolution_param { 579 | num_output: 256 580 | kernel_size: 3 581 | stride: 1 582 | pad: 1 583 | weight_filler { 584 | type: "gaussian" 585 | std: 0.01 586 | } 587 | bias_filler { 588 | type: "constant" 589 | value: 0 590 | } 591 | } 592 | } 593 | layer { 594 | name: "relu3_7" 595 | type: "PReLU" 596 | bottom: "conv3_7" 597 | top: "conv3_7" 598 | } 599 | layer { 600 | name: "res3_7" 601 | type: "Eltwise" 602 | bottom: "res3_5" 603 | bottom: "conv3_7" 604 | top: "res3_7" 605 | eltwise_param { 606 | operation: 1 607 | } 608 | } 609 | layer { 610 | name: "conv3_8" 611 | type: "Convolution" 612 | bottom: "res3_7" 613 | top: "conv3_8" 614 | param { 615 | lr_mult: 1 616 | decay_mult: 1 617 | } 618 | param { 619 | lr_mult: 0 620 | decay_mult: 0 621 | } 622 | convolution_param { 623 | num_output: 256 624 | kernel_size: 3 625 | stride: 1 626 | pad: 1 627 | weight_filler { 628 | type: "gaussian" 629 | std: 0.01 630 | } 631 | bias_filler { 632 | type: "constant" 633 | value: 0 634 | } 635 | } 636 | } 637 | layer { 638 | name: "relu3_8" 639 | type: "PReLU" 640 | bottom: "conv3_8" 641 | top: "conv3_8" 642 | } 643 | layer { 644 | name: "conv3_9" 645 | type: "Convolution" 646 | bottom: "conv3_8" 647 | top: "conv3_9" 648 | param { 649 | lr_mult: 1 650 | decay_mult: 1 651 | } 652 | param { 653 | lr_mult: 0 654 | decay_mult: 0 655 | } 656 | convolution_param { 657 | num_output: 256 658 | kernel_size: 3 659 | stride: 1 660 | pad: 1 661 | weight_filler { 662 | type: "gaussian" 663 | std: 0.01 664 | } 665 | bias_filler { 666 | type: "constant" 667 | value: 0 668 | } 669 | } 670 | } 671 | layer { 672 | name: "relu3_9" 673 | type: "PReLU" 674 | bottom: "conv3_9" 675 | top: "conv3_9" 676 | } 677 | layer { 678 | name: "res3_9" 679 | type: "Eltwise" 680 | bottom: "res3_7" 681 | bottom: "conv3_9" 682 | top: "res3_9" 683 | eltwise_param { 684 | operation: 1 685 | } 686 | } 687 | layer { 688 | name: "conv4_1" 689 | type: "Convolution" 690 | bottom: "res3_9" 691 | top: "conv4_1" 692 | param { 693 | lr_mult: 1 694 | decay_mult: 1 695 | } 696 | param { 697 | lr_mult: 2 698 | decay_mult: 0 699 | } 700 | convolution_param { 701 | num_output: 512 702 | kernel_size: 3 703 | stride: 2 704 | pad: 1 705 | weight_filler { 706 | type: "xavier" 707 | } 708 | bias_filler { 709 | type: "constant" 710 | value: 0 711 | } 712 | } 713 | } 714 | layer { 715 | name: "relu4_1" 716 | type: "PReLU" 717 | bottom: "conv4_1" 718 | top: "conv4_1" 719 | } 720 | layer { 721 | name: "conv4_2" 722 | type: "Convolution" 723 | bottom: "conv4_1" 724 | top: "conv4_2" 725 | param { 726 | lr_mult: 1 727 | decay_mult: 1 728 | } 729 | param { 730 | lr_mult: 0 731 | decay_mult: 0 732 | } 733 | convolution_param { 734 | num_output: 512 735 | kernel_size: 3 736 | stride: 1 737 | pad: 1 738 | weight_filler { 739 | type: "gaussian" 740 | std: 0.01 741 | } 742 | bias_filler { 743 | type: "constant" 744 | value: 0 745 | } 746 | } 747 | } 748 | layer { 749 | name: "relu4_2" 750 | type: "PReLU" 751 | bottom: "conv4_2" 752 | top: "conv4_2" 753 | } 754 | layer { 755 | name: "conv4_3" 756 | type: "Convolution" 757 | bottom: "conv4_2" 758 | top: "conv4_3" 759 | param { 760 | lr_mult: 1 761 | decay_mult: 1 762 | } 763 | param { 764 | lr_mult: 0 765 | decay_mult: 0 766 | } 767 | convolution_param { 768 | num_output: 512 769 | kernel_size: 3 770 | stride: 1 771 | pad: 1 772 | weight_filler { 773 | type: "gaussian" 774 | std: 0.01 775 | } 776 | bias_filler { 777 | type: "constant" 778 | value: 0 779 | } 780 | } 781 | } 782 | layer { 783 | name: "relu4_3" 784 | type: "PReLU" 785 | bottom: "conv4_3" 786 | top: "conv4_3" 787 | } 788 | layer { 789 | name: "res4_3" 790 | type: "Eltwise" 791 | bottom: "conv4_1" 792 | bottom: "conv4_3" 793 | top: "res4_3" 794 | eltwise_param { 795 | operation: 1 796 | } 797 | } 798 | layer { 799 | name: "fc5" 800 | type: "InnerProduct" 801 | bottom: "res4_3" 802 | top: "fc5" 803 | param { 804 | lr_mult: 1 805 | decay_mult: 1 806 | } 807 | param { 808 | lr_mult: 2 809 | decay_mult: 0 810 | } 811 | inner_product_param { 812 | num_output: 512 813 | weight_filler { 814 | type: "xavier" 815 | } 816 | bias_filler { 817 | type: "constant" 818 | value: 0 819 | } 820 | } 821 | } 822 | layer { 823 | name: "norm1" 824 | type: "Normalize" 825 | bottom: "fc5" 826 | top: "norm1" 827 | } 828 | layer { 829 | name: "fc6_l2" 830 | type: "InnerProduct" 831 | bottom: "norm1" 832 | top: "fc6" 833 | param { 834 | lr_mult: 1 835 | } 836 | inner_product_param{ 837 | num_output: 10516 838 | normalize: true 839 | weight_filler { 840 | type: "xavier" 841 | } 842 | bias_term: false 843 | } 844 | } 845 | layer { 846 | name: "label_specific_margin" 847 | type: "LabelSpecificAdd" 848 | bottom: "fc6" 849 | bottom: "label" 850 | top: "fc6_margin" 851 | label_specific_add_param { 852 | bias: -0.35 853 | } 854 | } 855 | layer { 856 | name: "fc6_margin_scale" 857 | type: "Scale" 858 | bottom: "fc6_margin" 859 | top: "fc6_margin_scale" 860 | param { 861 | lr_mult: 0 862 | decay_mult: 0 863 | } 864 | scale_param { 865 | min_value: 30 866 | filler{ 867 | type: "constant" 868 | value: 30 869 | } 870 | } 871 | } 872 | layer { 873 | name: "softmax_loss" 874 | type: "SoftmaxWithLoss" 875 | bottom: "fc6_margin_scale" 876 | bottom: "label" 877 | top: "softmax_loss" 878 | loss_weight: 1 879 | } 880 | layer { 881 | name: "Accuracy" 882 | type: "Accuracy" 883 | bottom: "fc6" 884 | bottom: "label" 885 | top: "accuracy" 886 | include { 887 | phase: TEST 888 | } 889 | } -------------------------------------------------------------------------------- /LFW/models/centerface/face_deploy.prototxt: -------------------------------------------------------------------------------- 1 | input: "data" 2 | input_dim: 1 3 | input_dim: 3 4 | input_dim: 112 5 | input_dim: 96 6 | layer { 7 | name: "conv1a" 8 | type: "Convolution" 9 | bottom: "data" 10 | top: "conv1a" 11 | param { 12 | lr_mult: 1 13 | decay_mult: 1 14 | } 15 | param { 16 | lr_mult: 2 17 | decay_mult: 0 18 | } 19 | convolution_param { 20 | num_output: 32 21 | kernel_size: 3 22 | stride: 1 23 | weight_filler { 24 | type: "xavier" 25 | } 26 | bias_filler { 27 | type: "constant" 28 | value: 0 29 | } 30 | } 31 | } 32 | layer { 33 | name: "relu1a" 34 | type: "PReLU" 35 | bottom: "conv1a" 36 | top: "conv1a" 37 | } 38 | layer { 39 | name: "conv1b" 40 | type: "Convolution" 41 | bottom: "conv1a" 42 | top: "conv1b" 43 | param { 44 | lr_mult: 1 45 | decay_mult: 1 46 | } 47 | param { 48 | lr_mult: 2 49 | decay_mult: 0 50 | } 51 | convolution_param { 52 | num_output: 64 53 | kernel_size: 3 54 | stride: 1 55 | weight_filler { 56 | type: "xavier" 57 | } 58 | bias_filler { 59 | type: "constant" 60 | value: 0 61 | } 62 | } 63 | } 64 | layer { 65 | name: "relu1b" 66 | type: "PReLU" 67 | bottom: "conv1b" 68 | top: "conv1b" 69 | } 70 | layer { 71 | name: "pool1b" 72 | type: "Pooling" 73 | bottom: "conv1b" 74 | top: "pool1b" 75 | pooling_param { 76 | pool: MAX 77 | kernel_size: 2 78 | stride: 2 79 | } 80 | } 81 | layer { 82 | name: "conv2_1" 83 | type: "Convolution" 84 | bottom: "pool1b" 85 | top: "conv2_1" 86 | param { 87 | lr_mult: 1 88 | decay_mult: 1 89 | } 90 | param { 91 | lr_mult: 0 92 | decay_mult: 0 93 | } 94 | convolution_param { 95 | num_output: 64 96 | kernel_size: 3 97 | stride: 1 98 | pad: 1 99 | weight_filler { 100 | type: "gaussian" 101 | std: 0.01 102 | } 103 | bias_filler { 104 | type: "constant" 105 | value: 0 106 | } 107 | } 108 | } 109 | layer { 110 | name: "relu2_1" 111 | type: "PReLU" 112 | bottom: "conv2_1" 113 | top: "conv2_1" 114 | } 115 | layer { 116 | name: "conv2_2" 117 | type: "Convolution" 118 | bottom: "conv2_1" 119 | top: "conv2_2" 120 | param { 121 | lr_mult: 1 122 | decay_mult: 1 123 | } 124 | param { 125 | lr_mult: 0 126 | decay_mult: 0 127 | } 128 | convolution_param { 129 | num_output: 64 130 | kernel_size: 3 131 | stride: 1 132 | pad: 1 133 | weight_filler { 134 | type: "gaussian" 135 | std: 0.01 136 | } 137 | bias_filler { 138 | type: "constant" 139 | value: 0 140 | } 141 | } 142 | } 143 | layer { 144 | name: "relu2_2" 145 | type: "PReLU" 146 | bottom: "conv2_2" 147 | top: "conv2_2" 148 | } 149 | layer { 150 | name: "res2_2" 151 | type: "Eltwise" 152 | bottom: "pool1b" 153 | bottom: "conv2_2" 154 | top: "res2_2" 155 | eltwise_param { 156 | operation: 1 157 | } 158 | } 159 | layer { 160 | name: "conv2" 161 | type: "Convolution" 162 | bottom: "res2_2" 163 | top: "conv2" 164 | param { 165 | lr_mult: 1 166 | decay_mult: 1 167 | } 168 | param { 169 | lr_mult: 2 170 | decay_mult: 0 171 | } 172 | convolution_param { 173 | num_output: 128 174 | kernel_size: 3 175 | stride: 1 176 | weight_filler { 177 | type: "xavier" 178 | } 179 | bias_filler { 180 | type: "constant" 181 | value: 0 182 | } 183 | } 184 | } 185 | layer { 186 | name: "relu2" 187 | type: "PReLU" 188 | bottom: "conv2" 189 | top: "conv2" 190 | } 191 | layer { 192 | name: "pool2" 193 | type: "Pooling" 194 | bottom: "conv2" 195 | top: "pool2" 196 | pooling_param { 197 | pool: MAX 198 | kernel_size: 2 199 | stride: 2 200 | } 201 | } 202 | layer { 203 | name: "conv3_1" 204 | type: "Convolution" 205 | bottom: "pool2" 206 | top: "conv3_1" 207 | param { 208 | lr_mult: 1 209 | decay_mult: 1 210 | } 211 | param { 212 | lr_mult: 0 213 | decay_mult: 0 214 | } 215 | convolution_param { 216 | num_output: 128 217 | kernel_size: 3 218 | stride: 1 219 | pad: 1 220 | weight_filler { 221 | type: "gaussian" 222 | std: 0.01 223 | } 224 | bias_filler { 225 | type: "constant" 226 | value: 0 227 | } 228 | } 229 | } 230 | layer { 231 | name: "relu3_1" 232 | type: "PReLU" 233 | bottom: "conv3_1" 234 | top: "conv3_1" 235 | } 236 | layer { 237 | name: "conv3_2" 238 | type: "Convolution" 239 | bottom: "conv3_1" 240 | top: "conv3_2" 241 | param { 242 | lr_mult: 1 243 | decay_mult: 1 244 | } 245 | param { 246 | lr_mult: 0 247 | decay_mult: 0 248 | } 249 | convolution_param { 250 | num_output: 128 251 | kernel_size: 3 252 | stride: 1 253 | pad: 1 254 | weight_filler { 255 | type: "gaussian" 256 | std: 0.01 257 | } 258 | bias_filler { 259 | type: "constant" 260 | value: 0 261 | } 262 | } 263 | } 264 | layer { 265 | name: "relu3_2" 266 | type: "PReLU" 267 | bottom: "conv3_2" 268 | top: "conv3_2" 269 | } 270 | layer { 271 | name: "res3_2" 272 | type: "Eltwise" 273 | bottom: "pool2" 274 | bottom: "conv3_2" 275 | top: "res3_2" 276 | eltwise_param { 277 | operation: 1 278 | } 279 | } 280 | layer { 281 | name: "conv3_3" 282 | type: "Convolution" 283 | bottom: "res3_2" 284 | top: "conv3_3" 285 | param { 286 | lr_mult: 1 287 | decay_mult: 1 288 | } 289 | param { 290 | lr_mult: 0 291 | decay_mult: 0 292 | } 293 | convolution_param { 294 | num_output: 128 295 | kernel_size: 3 296 | stride: 1 297 | pad: 1 298 | weight_filler { 299 | type: "gaussian" 300 | std: 0.01 301 | } 302 | bias_filler { 303 | type: "constant" 304 | value: 0 305 | } 306 | } 307 | } 308 | layer { 309 | name: "relu3_3" 310 | type: "PReLU" 311 | bottom: "conv3_3" 312 | top: "conv3_3" 313 | } 314 | layer { 315 | name: "conv3_4" 316 | type: "Convolution" 317 | bottom: "conv3_3" 318 | top: "conv3_4" 319 | param { 320 | lr_mult: 1 321 | decay_mult: 1 322 | } 323 | param { 324 | lr_mult: 0 325 | decay_mult: 0 326 | } 327 | convolution_param { 328 | num_output: 128 329 | kernel_size: 3 330 | stride: 1 331 | pad: 1 332 | weight_filler { 333 | type: "gaussian" 334 | std: 0.01 335 | } 336 | bias_filler { 337 | type: "constant" 338 | value: 0 339 | } 340 | } 341 | } 342 | layer { 343 | name: "relu3_4" 344 | type: "PReLU" 345 | bottom: "conv3_4" 346 | top: "conv3_4" 347 | } 348 | layer { 349 | name: "res3_4" 350 | type: "Eltwise" 351 | bottom: "res3_2" 352 | bottom: "conv3_4" 353 | top: "res3_4" 354 | eltwise_param { 355 | operation: 1 356 | } 357 | } 358 | 359 | layer { 360 | name: "conv3" 361 | type: "Convolution" 362 | bottom: "res3_4" 363 | top: "conv3" 364 | param { 365 | lr_mult: 1 366 | decay_mult: 1 367 | } 368 | param { 369 | lr_mult: 2 370 | decay_mult: 0 371 | } 372 | convolution_param { 373 | num_output: 256 374 | kernel_size: 3 375 | stride: 1 376 | weight_filler { 377 | type: "xavier" 378 | } 379 | bias_filler { 380 | type: "constant" 381 | value: 0 382 | } 383 | } 384 | } 385 | layer { 386 | name: "relu3" 387 | type: "PReLU" 388 | bottom: "conv3" 389 | top: "conv3" 390 | } 391 | layer { 392 | name: "pool3" 393 | type: "Pooling" 394 | bottom: "conv3" 395 | top: "pool3" 396 | pooling_param { 397 | pool: MAX 398 | kernel_size: 2 399 | stride: 2 400 | } 401 | } 402 | layer { 403 | name: "conv4_1" 404 | type: "Convolution" 405 | bottom: "pool3" 406 | top: "conv4_1" 407 | param { 408 | lr_mult: 1 409 | decay_mult: 1 410 | } 411 | param { 412 | lr_mult: 0 413 | decay_mult: 0 414 | } 415 | convolution_param { 416 | num_output: 256 417 | kernel_size: 3 418 | stride: 1 419 | pad: 1 420 | weight_filler { 421 | type: "gaussian" 422 | std: 0.01 423 | } 424 | bias_filler { 425 | type: "constant" 426 | value: 0 427 | } 428 | } 429 | } 430 | layer { 431 | name: "relu4_1" 432 | type: "PReLU" 433 | bottom: "conv4_1" 434 | top: "conv4_1" 435 | } 436 | layer { 437 | name: "conv4_2" 438 | type: "Convolution" 439 | bottom: "conv4_1" 440 | top: "conv4_2" 441 | param { 442 | lr_mult: 1 443 | decay_mult: 1 444 | } 445 | param { 446 | lr_mult: 0 447 | decay_mult: 0 448 | } 449 | convolution_param { 450 | num_output: 256 451 | kernel_size: 3 452 | stride: 1 453 | pad: 1 454 | weight_filler { 455 | type: "gaussian" 456 | std: 0.01 457 | } 458 | bias_filler { 459 | type: "constant" 460 | value: 0 461 | } 462 | } 463 | } 464 | layer { 465 | name: "relu4_2" 466 | type: "PReLU" 467 | bottom: "conv4_2" 468 | top: "conv4_2" 469 | } 470 | layer { 471 | name: "res4_2" 472 | type: "Eltwise" 473 | bottom: "pool3" 474 | bottom: "conv4_2" 475 | top: "res4_2" 476 | eltwise_param { 477 | operation: 1 478 | } 479 | } 480 | layer { 481 | name: "conv4_3" 482 | type: "Convolution" 483 | bottom: "res4_2" 484 | top: "conv4_3" 485 | param { 486 | lr_mult: 1 487 | decay_mult: 1 488 | } 489 | param { 490 | lr_mult: 0 491 | decay_mult: 0 492 | } 493 | convolution_param { 494 | num_output: 256 495 | kernel_size: 3 496 | stride: 1 497 | pad: 1 498 | weight_filler { 499 | type: "gaussian" 500 | std: 0.01 501 | } 502 | bias_filler { 503 | type: "constant" 504 | value: 0 505 | } 506 | } 507 | } 508 | layer { 509 | name: "relu4_3" 510 | type: "PReLU" 511 | bottom: "conv4_3" 512 | top: "conv4_3" 513 | } 514 | layer { 515 | name: "conv4_4" 516 | type: "Convolution" 517 | bottom: "conv4_3" 518 | top: "conv4_4" 519 | param { 520 | lr_mult: 1 521 | decay_mult: 1 522 | } 523 | param { 524 | lr_mult: 0 525 | decay_mult: 0 526 | } 527 | convolution_param { 528 | num_output: 256 529 | kernel_size: 3 530 | stride: 1 531 | pad: 1 532 | weight_filler { 533 | type: "gaussian" 534 | std: 0.01 535 | } 536 | bias_filler { 537 | type: "constant" 538 | value: 0 539 | } 540 | } 541 | } 542 | layer { 543 | name: "relu4_4" 544 | type: "PReLU" 545 | bottom: "conv4_4" 546 | top: "conv4_4" 547 | } 548 | layer { 549 | name: "res4_4" 550 | type: "Eltwise" 551 | bottom: "res4_2" 552 | bottom: "conv4_4" 553 | top: "res4_4" 554 | eltwise_param { 555 | operation: 1 556 | } 557 | } 558 | layer { 559 | name: "conv4_5" 560 | type: "Convolution" 561 | bottom: "res4_4" 562 | top: "conv4_5" 563 | param { 564 | lr_mult: 1 565 | decay_mult: 1 566 | } 567 | param { 568 | lr_mult: 0 569 | decay_mult: 0 570 | } 571 | convolution_param { 572 | num_output: 256 573 | kernel_size: 3 574 | stride: 1 575 | pad: 1 576 | weight_filler { 577 | type: "gaussian" 578 | std: 0.01 579 | } 580 | bias_filler { 581 | type: "constant" 582 | value: 0 583 | } 584 | } 585 | } 586 | layer { 587 | name: "relu4_5" 588 | type: "PReLU" 589 | bottom: "conv4_5" 590 | top: "conv4_5" 591 | } 592 | layer { 593 | name: "conv4_6" 594 | type: "Convolution" 595 | bottom: "conv4_5" 596 | top: "conv4_6" 597 | param { 598 | lr_mult: 1 599 | decay_mult: 1 600 | } 601 | param { 602 | lr_mult: 0 603 | decay_mult: 0 604 | } 605 | convolution_param { 606 | num_output: 256 607 | kernel_size: 3 608 | stride: 1 609 | pad: 1 610 | weight_filler { 611 | type: "gaussian" 612 | std: 0.01 613 | } 614 | bias_filler { 615 | type: "constant" 616 | value: 0 617 | } 618 | } 619 | } 620 | layer { 621 | name: "relu4_6" 622 | type: "PReLU" 623 | bottom: "conv4_6" 624 | top: "conv4_6" 625 | } 626 | layer { 627 | name: "res4_6" 628 | type: "Eltwise" 629 | bottom: "res4_4" 630 | bottom: "conv4_6" 631 | top: "res4_6" 632 | eltwise_param { 633 | operation: 1 634 | } 635 | } 636 | layer { 637 | name: "conv4_7" 638 | type: "Convolution" 639 | bottom: "res4_6" 640 | top: "conv4_7" 641 | param { 642 | lr_mult: 1 643 | decay_mult: 1 644 | } 645 | param { 646 | lr_mult: 0 647 | decay_mult: 0 648 | } 649 | convolution_param { 650 | num_output: 256 651 | kernel_size: 3 652 | stride: 1 653 | pad: 1 654 | weight_filler { 655 | type: "gaussian" 656 | std: 0.01 657 | } 658 | bias_filler { 659 | type: "constant" 660 | value: 0 661 | } 662 | } 663 | } 664 | layer { 665 | name: "relu4_7" 666 | type: "PReLU" 667 | bottom: "conv4_7" 668 | top: "conv4_7" 669 | } 670 | layer { 671 | name: "conv4_8" 672 | type: "Convolution" 673 | bottom: "conv4_7" 674 | top: "conv4_8" 675 | param { 676 | lr_mult: 1 677 | decay_mult: 1 678 | } 679 | param { 680 | lr_mult: 0 681 | decay_mult: 0 682 | } 683 | convolution_param { 684 | num_output: 256 685 | kernel_size: 3 686 | stride: 1 687 | pad: 1 688 | weight_filler { 689 | type: "gaussian" 690 | std: 0.01 691 | } 692 | bias_filler { 693 | type: "constant" 694 | value: 0 695 | } 696 | } 697 | } 698 | layer { 699 | name: "relu4_8" 700 | type: "PReLU" 701 | bottom: "conv4_8" 702 | top: "conv4_8" 703 | } 704 | layer { 705 | name: "res4_8" 706 | type: "Eltwise" 707 | bottom: "res4_6" 708 | bottom: "conv4_8" 709 | top: "res4_8" 710 | eltwise_param { 711 | operation: 1 712 | } 713 | } 714 | layer { 715 | name: "conv4_9" 716 | type: "Convolution" 717 | bottom: "res4_8" 718 | top: "conv4_9" 719 | param { 720 | lr_mult: 1 721 | decay_mult: 1 722 | } 723 | param { 724 | lr_mult: 0 725 | decay_mult: 0 726 | } 727 | convolution_param { 728 | num_output: 256 729 | kernel_size: 3 730 | stride: 1 731 | pad: 1 732 | weight_filler { 733 | type: "gaussian" 734 | std: 0.01 735 | } 736 | bias_filler { 737 | type: "constant" 738 | value: 0 739 | } 740 | } 741 | } 742 | layer { 743 | name: "relu4_9" 744 | type: "PReLU" 745 | bottom: "conv4_9" 746 | top: "conv4_9" 747 | } 748 | layer { 749 | name: "conv4_10" 750 | type: "Convolution" 751 | bottom: "conv4_9" 752 | top: "conv4_10" 753 | param { 754 | lr_mult: 1 755 | decay_mult: 1 756 | } 757 | param { 758 | lr_mult: 0 759 | decay_mult: 0 760 | } 761 | convolution_param { 762 | num_output: 256 763 | kernel_size: 3 764 | stride: 1 765 | pad: 1 766 | weight_filler { 767 | type: "gaussian" 768 | std: 0.01 769 | } 770 | bias_filler { 771 | type: "constant" 772 | value: 0 773 | } 774 | } 775 | } 776 | layer { 777 | name: "relu4_10" 778 | type: "PReLU" 779 | bottom: "conv4_10" 780 | top: "conv4_10" 781 | } 782 | layer { 783 | name: "res4_10" 784 | type: "Eltwise" 785 | bottom: "res4_8" 786 | bottom: "conv4_10" 787 | top: "res4_10" 788 | eltwise_param { 789 | operation: 1 790 | } 791 | } 792 | layer { 793 | name: "conv4" 794 | type: "Convolution" 795 | bottom: "res4_10" 796 | top: "conv4" 797 | param { 798 | lr_mult: 1 799 | decay_mult: 1 800 | } 801 | param { 802 | lr_mult: 2 803 | decay_mult: 0 804 | } 805 | convolution_param { 806 | num_output: 512 807 | kernel_size: 3 808 | stride: 1 809 | weight_filler { 810 | type: "xavier" 811 | } 812 | bias_filler { 813 | type: "constant" 814 | value: 0 815 | } 816 | } 817 | } 818 | layer { 819 | name: "relu4" 820 | type: "PReLU" 821 | bottom: "conv4" 822 | top: "conv4" 823 | } 824 | layer { 825 | name: "pool4" 826 | type: "Pooling" 827 | bottom: "conv4" 828 | top: "pool4" 829 | pooling_param { 830 | pool: MAX 831 | kernel_size: 2 832 | stride: 2 833 | } 834 | } 835 | layer { 836 | name: "conv5_1" 837 | type: "Convolution" 838 | bottom: "pool4" 839 | top: "conv5_1" 840 | param { 841 | lr_mult: 1 842 | decay_mult: 1 843 | } 844 | param { 845 | lr_mult: 0 846 | decay_mult: 0 847 | } 848 | convolution_param { 849 | num_output: 512 850 | kernel_size: 3 851 | stride: 1 852 | pad: 1 853 | weight_filler { 854 | type: "gaussian" 855 | std: 0.01 856 | } 857 | bias_filler { 858 | type: "constant" 859 | value: 0 860 | } 861 | } 862 | } 863 | layer { 864 | name: "relu5_1" 865 | type: "PReLU" 866 | bottom: "conv5_1" 867 | top: "conv5_1" 868 | } 869 | layer { 870 | name: "conv5_2" 871 | type: "Convolution" 872 | bottom: "conv5_1" 873 | top: "conv5_2" 874 | param { 875 | lr_mult: 1 876 | decay_mult: 1 877 | } 878 | param { 879 | lr_mult: 0 880 | decay_mult: 0 881 | } 882 | convolution_param { 883 | num_output: 512 884 | kernel_size: 3 885 | stride: 1 886 | pad: 1 887 | weight_filler { 888 | type: "gaussian" 889 | std: 0.01 890 | } 891 | bias_filler { 892 | type: "constant" 893 | value: 0 894 | } 895 | } 896 | } 897 | layer { 898 | name: "relu5_2" 899 | type: "PReLU" 900 | bottom: "conv5_2" 901 | top: "conv5_2" 902 | } 903 | layer { 904 | name: "res5_2" 905 | type: "Eltwise" 906 | bottom: "pool4" 907 | bottom: "conv5_2" 908 | top: "res5_2" 909 | eltwise_param { 910 | operation: 1 911 | } 912 | } 913 | layer { 914 | name: "conv5_3" 915 | type: "Convolution" 916 | bottom: "res5_2" 917 | top: "conv5_3" 918 | param { 919 | lr_mult: 1 920 | decay_mult: 1 921 | } 922 | param { 923 | lr_mult: 0 924 | decay_mult: 0 925 | } 926 | convolution_param { 927 | num_output: 512 928 | kernel_size: 3 929 | stride: 1 930 | pad: 1 931 | weight_filler { 932 | type: "gaussian" 933 | std: 0.01 934 | } 935 | bias_filler { 936 | type: "constant" 937 | value: 0 938 | } 939 | } 940 | } 941 | layer { 942 | name: "relu5_3" 943 | type: "PReLU" 944 | bottom: "conv5_3" 945 | top: "conv5_3" 946 | } 947 | layer { 948 | name: "conv5_4" 949 | type: "Convolution" 950 | bottom: "conv5_3" 951 | top: "conv5_4" 952 | param { 953 | lr_mult: 1 954 | decay_mult: 1 955 | } 956 | param { 957 | lr_mult: 0 958 | decay_mult: 0 959 | } 960 | convolution_param { 961 | num_output: 512 962 | kernel_size: 3 963 | stride: 1 964 | pad: 1 965 | weight_filler { 966 | type: "gaussian" 967 | std: 0.01 968 | } 969 | bias_filler { 970 | type: "constant" 971 | value: 0 972 | } 973 | } 974 | } 975 | layer { 976 | name: "relu5_4" 977 | type: "PReLU" 978 | bottom: "conv5_4" 979 | top: "conv5_4" 980 | } 981 | layer { 982 | name: "res5_4" 983 | type: "Eltwise" 984 | bottom: "res5_2" 985 | bottom: "conv5_4" 986 | top: "res5_4" 987 | eltwise_param { 988 | operation: 1 989 | } 990 | } 991 | layer { 992 | name: "conv5_5" 993 | type: "Convolution" 994 | bottom: "res5_4" 995 | top: "conv5_5" 996 | param { 997 | lr_mult: 1 998 | decay_mult: 1 999 | } 1000 | param { 1001 | lr_mult: 0 1002 | decay_mult: 0 1003 | } 1004 | convolution_param { 1005 | num_output: 512 1006 | kernel_size: 3 1007 | stride: 1 1008 | pad: 1 1009 | weight_filler { 1010 | type: "gaussian" 1011 | std: 0.01 1012 | } 1013 | bias_filler { 1014 | type: "constant" 1015 | value: 0 1016 | } 1017 | } 1018 | } 1019 | layer { 1020 | name: "relu5_5" 1021 | type: "PReLU" 1022 | bottom: "conv5_5" 1023 | top: "conv5_5" 1024 | } 1025 | layer { 1026 | name: "conv5_6" 1027 | type: "Convolution" 1028 | bottom: "conv5_5" 1029 | top: "conv5_6" 1030 | param { 1031 | lr_mult: 1 1032 | decay_mult: 1 1033 | } 1034 | param { 1035 | lr_mult: 0 1036 | decay_mult: 0 1037 | } 1038 | convolution_param { 1039 | num_output: 512 1040 | kernel_size: 3 1041 | stride: 1 1042 | pad: 1 1043 | weight_filler { 1044 | type: "gaussian" 1045 | std: 0.01 1046 | } 1047 | bias_filler { 1048 | type: "constant" 1049 | value: 0 1050 | } 1051 | } 1052 | } 1053 | layer { 1054 | name: "relu5_6" 1055 | type: "PReLU" 1056 | bottom: "conv5_6" 1057 | top: "conv5_6" 1058 | } 1059 | layer { 1060 | name: "res5_6" 1061 | type: "Eltwise" 1062 | bottom: "res5_4" 1063 | bottom: "conv5_6" 1064 | top: "res5_6" 1065 | eltwise_param { 1066 | operation: 1 1067 | } 1068 | } 1069 | layer { 1070 | name: "fc5" 1071 | type: "InnerProduct" 1072 | bottom: "res5_6" 1073 | top: "fc5" 1074 | param { 1075 | lr_mult: 1 1076 | decay_mult: 1 1077 | } 1078 | param { 1079 | lr_mult: 2 1080 | decay_mult: 0 1081 | } 1082 | inner_product_param { 1083 | num_output: 512 1084 | weight_filler { 1085 | type: "xavier" 1086 | } 1087 | bias_filler { 1088 | type: "constant" 1089 | value: 0 1090 | } 1091 | } 1092 | } 1093 | -------------------------------------------------------------------------------- /LFW/models/sphereface/sphereface_deploy.prototxt: -------------------------------------------------------------------------------- 1 | name: "SpherefaceNet-20" 2 | input: "data" 3 | input_dim: 1 4 | input_dim: 3 5 | input_dim: 112 6 | input_dim: 96 7 | ############## CNN Architecture ############### 8 | layer { 9 | name: "conv1_1" 10 | type: "Convolution" 11 | bottom: "data" 12 | top: "conv1_1" 13 | param { 14 | lr_mult: 1 15 | decay_mult: 1 16 | } 17 | param { 18 | lr_mult: 2 19 | decay_mult: 0 20 | } 21 | convolution_param { 22 | num_output: 64 23 | kernel_size: 3 24 | stride: 2 25 | pad: 1 26 | weight_filler { 27 | type: "xavier" 28 | } 29 | bias_filler { 30 | type: "constant" 31 | value: 0 32 | } 33 | } 34 | } 35 | layer { 36 | name: "relu1_1" 37 | type: "PReLU" 38 | bottom: "conv1_1" 39 | top: "conv1_1" 40 | } 41 | layer { 42 | name: "conv1_2" 43 | type: "Convolution" 44 | bottom: "conv1_1" 45 | top: "conv1_2" 46 | param { 47 | lr_mult: 1 48 | decay_mult: 1 49 | } 50 | param { 51 | lr_mult: 0 52 | decay_mult: 0 53 | } 54 | convolution_param { 55 | num_output: 64 56 | kernel_size: 3 57 | stride: 1 58 | pad: 1 59 | weight_filler { 60 | type: "gaussian" 61 | std: 0.01 62 | } 63 | bias_filler { 64 | type: "constant" 65 | value: 0 66 | } 67 | } 68 | } 69 | layer { 70 | name: "relu1_2" 71 | type: "PReLU" 72 | bottom: "conv1_2" 73 | top: "conv1_2" 74 | } 75 | layer { 76 | name: "conv1_3" 77 | type: "Convolution" 78 | bottom: "conv1_2" 79 | top: "conv1_3" 80 | param { 81 | lr_mult: 1 82 | decay_mult: 1 83 | } 84 | param { 85 | lr_mult: 0 86 | decay_mult: 0 87 | } 88 | convolution_param { 89 | num_output: 64 90 | kernel_size: 3 91 | stride: 1 92 | pad: 1 93 | weight_filler { 94 | type: "gaussian" 95 | std: 0.01 96 | } 97 | bias_filler { 98 | type: "constant" 99 | value: 0 100 | } 101 | } 102 | } 103 | layer { 104 | name: "relu1_3" 105 | type: "PReLU" 106 | bottom: "conv1_3" 107 | top: "conv1_3" 108 | } 109 | layer { 110 | name: "res1_3" 111 | type: "Eltwise" 112 | bottom: "conv1_1" 113 | bottom: "conv1_3" 114 | top: "res1_3" 115 | eltwise_param { 116 | operation: 1 117 | } 118 | } 119 | layer { 120 | name: "conv2_1" 121 | type: "Convolution" 122 | bottom: "res1_3" 123 | top: "conv2_1" 124 | param { 125 | lr_mult: 1 126 | decay_mult: 1 127 | } 128 | param { 129 | lr_mult: 2 130 | decay_mult: 0 131 | } 132 | convolution_param { 133 | num_output: 128 134 | kernel_size: 3 135 | stride: 2 136 | pad: 1 137 | weight_filler { 138 | type: "xavier" 139 | } 140 | bias_filler { 141 | type: "constant" 142 | value: 0 143 | } 144 | } 145 | } 146 | layer { 147 | name: "relu2_1" 148 | type: "PReLU" 149 | bottom: "conv2_1" 150 | top: "conv2_1" 151 | } 152 | layer { 153 | name: "conv2_2" 154 | type: "Convolution" 155 | bottom: "conv2_1" 156 | top: "conv2_2" 157 | param { 158 | lr_mult: 1 159 | decay_mult: 1 160 | } 161 | param { 162 | lr_mult: 0 163 | decay_mult: 0 164 | } 165 | convolution_param { 166 | num_output: 128 167 | kernel_size: 3 168 | stride: 1 169 | pad: 1 170 | weight_filler { 171 | type: "gaussian" 172 | std: 0.01 173 | } 174 | bias_filler { 175 | type: "constant" 176 | value: 0 177 | } 178 | } 179 | } 180 | layer { 181 | name: "relu2_2" 182 | type: "PReLU" 183 | bottom: "conv2_2" 184 | top: "conv2_2" 185 | } 186 | layer { 187 | name: "conv2_3" 188 | type: "Convolution" 189 | bottom: "conv2_2" 190 | top: "conv2_3" 191 | param { 192 | lr_mult: 1 193 | decay_mult: 1 194 | } 195 | param { 196 | lr_mult: 0 197 | decay_mult: 0 198 | } 199 | convolution_param { 200 | num_output: 128 201 | kernel_size: 3 202 | stride: 1 203 | pad: 1 204 | weight_filler { 205 | type: "gaussian" 206 | std: 0.01 207 | } 208 | bias_filler { 209 | type: "constant" 210 | value: 0 211 | } 212 | } 213 | } 214 | layer { 215 | name: "relu2_3" 216 | type: "PReLU" 217 | bottom: "conv2_3" 218 | top: "conv2_3" 219 | } 220 | layer { 221 | name: "res2_3" 222 | type: "Eltwise" 223 | bottom: "conv2_1" 224 | bottom: "conv2_3" 225 | top: "res2_3" 226 | eltwise_param { 227 | operation: 1 228 | } 229 | } 230 | layer { 231 | name: "conv2_4" 232 | type: "Convolution" 233 | bottom: "res2_3" 234 | top: "conv2_4" 235 | param { 236 | lr_mult: 1 237 | decay_mult: 1 238 | } 239 | param { 240 | lr_mult: 0 241 | decay_mult: 0 242 | } 243 | convolution_param { 244 | num_output: 128 245 | kernel_size: 3 246 | stride: 1 247 | pad: 1 248 | weight_filler { 249 | type: "gaussian" 250 | std: 0.01 251 | } 252 | bias_filler { 253 | type: "constant" 254 | value: 0 255 | } 256 | } 257 | } 258 | layer { 259 | name: "relu2_4" 260 | type: "PReLU" 261 | bottom: "conv2_4" 262 | top: "conv2_4" 263 | } 264 | layer { 265 | name: "conv2_5" 266 | type: "Convolution" 267 | bottom: "conv2_4" 268 | top: "conv2_5" 269 | param { 270 | lr_mult: 1 271 | decay_mult: 1 272 | } 273 | param { 274 | lr_mult: 0 275 | decay_mult: 0 276 | } 277 | convolution_param { 278 | num_output: 128 279 | kernel_size: 3 280 | stride: 1 281 | pad: 1 282 | weight_filler { 283 | type: "gaussian" 284 | std: 0.01 285 | } 286 | bias_filler { 287 | type: "constant" 288 | value: 0 289 | } 290 | } 291 | } 292 | layer { 293 | name: "relu2_5" 294 | type: "PReLU" 295 | bottom: "conv2_5" 296 | top: "conv2_5" 297 | } 298 | layer { 299 | name: "res2_5" 300 | type: "Eltwise" 301 | bottom: "res2_3" 302 | bottom: "conv2_5" 303 | top: "res2_5" 304 | eltwise_param { 305 | operation: 1 306 | } 307 | } 308 | layer { 309 | name: "conv3_1" 310 | type: "Convolution" 311 | bottom: "res2_5" 312 | top: "conv3_1" 313 | param { 314 | lr_mult: 1 315 | decay_mult: 1 316 | } 317 | param { 318 | lr_mult: 2 319 | decay_mult: 0 320 | } 321 | convolution_param { 322 | num_output: 256 323 | kernel_size: 3 324 | stride: 2 325 | pad: 1 326 | weight_filler { 327 | type: "xavier" 328 | } 329 | bias_filler { 330 | type: "constant" 331 | value: 0 332 | } 333 | } 334 | } 335 | layer { 336 | name: "relu3_1" 337 | type: "PReLU" 338 | bottom: "conv3_1" 339 | top: "conv3_1" 340 | } 341 | layer { 342 | name: "conv3_2" 343 | type: "Convolution" 344 | bottom: "conv3_1" 345 | top: "conv3_2" 346 | param { 347 | lr_mult: 1 348 | decay_mult: 1 349 | } 350 | param { 351 | lr_mult: 0 352 | decay_mult: 0 353 | } 354 | convolution_param { 355 | num_output: 256 356 | kernel_size: 3 357 | stride: 1 358 | pad: 1 359 | weight_filler { 360 | type: "gaussian" 361 | std: 0.01 362 | } 363 | bias_filler { 364 | type: "constant" 365 | value: 0 366 | } 367 | } 368 | } 369 | layer { 370 | name: "relu3_2" 371 | type: "PReLU" 372 | bottom: "conv3_2" 373 | top: "conv3_2" 374 | } 375 | layer { 376 | name: "conv3_3" 377 | type: "Convolution" 378 | bottom: "conv3_2" 379 | top: "conv3_3" 380 | param { 381 | lr_mult: 1 382 | decay_mult: 1 383 | } 384 | param { 385 | lr_mult: 0 386 | decay_mult: 0 387 | } 388 | convolution_param { 389 | num_output: 256 390 | kernel_size: 3 391 | stride: 1 392 | pad: 1 393 | weight_filler { 394 | type: "gaussian" 395 | std: 0.01 396 | } 397 | bias_filler { 398 | type: "constant" 399 | value: 0 400 | } 401 | } 402 | } 403 | layer { 404 | name: "relu3_3" 405 | type: "PReLU" 406 | bottom: "conv3_3" 407 | top: "conv3_3" 408 | } 409 | layer { 410 | name: "res3_3" 411 | type: "Eltwise" 412 | bottom: "conv3_1" 413 | bottom: "conv3_3" 414 | top: "res3_3" 415 | eltwise_param { 416 | operation: 1 417 | } 418 | } 419 | layer { 420 | name: "conv3_4" 421 | type: "Convolution" 422 | bottom: "res3_3" 423 | top: "conv3_4" 424 | param { 425 | lr_mult: 1 426 | decay_mult: 1 427 | } 428 | param { 429 | lr_mult: 0 430 | decay_mult: 0 431 | } 432 | convolution_param { 433 | num_output: 256 434 | kernel_size: 3 435 | stride: 1 436 | pad: 1 437 | weight_filler { 438 | type: "gaussian" 439 | std: 0.01 440 | } 441 | bias_filler { 442 | type: "constant" 443 | value: 0 444 | } 445 | } 446 | } 447 | layer { 448 | name: "relu3_4" 449 | type: "PReLU" 450 | bottom: "conv3_4" 451 | top: "conv3_4" 452 | } 453 | layer { 454 | name: "conv3_5" 455 | type: "Convolution" 456 | bottom: "conv3_4" 457 | top: "conv3_5" 458 | param { 459 | lr_mult: 1 460 | decay_mult: 1 461 | } 462 | param { 463 | lr_mult: 0 464 | decay_mult: 0 465 | } 466 | convolution_param { 467 | num_output: 256 468 | kernel_size: 3 469 | stride: 1 470 | pad: 1 471 | weight_filler { 472 | type: "gaussian" 473 | std: 0.01 474 | } 475 | bias_filler { 476 | type: "constant" 477 | value: 0 478 | } 479 | } 480 | } 481 | layer { 482 | name: "relu3_5" 483 | type: "PReLU" 484 | bottom: "conv3_5" 485 | top: "conv3_5" 486 | } 487 | layer { 488 | name: "res3_5" 489 | type: "Eltwise" 490 | bottom: "res3_3" 491 | bottom: "conv3_5" 492 | top: "res3_5" 493 | eltwise_param { 494 | operation: 1 495 | } 496 | } 497 | layer { 498 | name: "conv3_6" 499 | type: "Convolution" 500 | bottom: "res3_5" 501 | top: "conv3_6" 502 | param { 503 | lr_mult: 1 504 | decay_mult: 1 505 | } 506 | param { 507 | lr_mult: 0 508 | decay_mult: 0 509 | } 510 | convolution_param { 511 | num_output: 256 512 | kernel_size: 3 513 | stride: 1 514 | pad: 1 515 | weight_filler { 516 | type: "gaussian" 517 | std: 0.01 518 | } 519 | bias_filler { 520 | type: "constant" 521 | value: 0 522 | } 523 | } 524 | } 525 | layer { 526 | name: "relu3_6" 527 | type: "PReLU" 528 | bottom: "conv3_6" 529 | top: "conv3_6" 530 | } 531 | layer { 532 | name: "conv3_7" 533 | type: "Convolution" 534 | bottom: "conv3_6" 535 | top: "conv3_7" 536 | param { 537 | lr_mult: 1 538 | decay_mult: 1 539 | } 540 | param { 541 | lr_mult: 0 542 | decay_mult: 0 543 | } 544 | convolution_param { 545 | num_output: 256 546 | kernel_size: 3 547 | stride: 1 548 | pad: 1 549 | weight_filler { 550 | type: "gaussian" 551 | std: 0.01 552 | } 553 | bias_filler { 554 | type: "constant" 555 | value: 0 556 | } 557 | } 558 | } 559 | layer { 560 | name: "relu3_7" 561 | type: "PReLU" 562 | bottom: "conv3_7" 563 | top: "conv3_7" 564 | } 565 | layer { 566 | name: "res3_7" 567 | type: "Eltwise" 568 | bottom: "res3_5" 569 | bottom: "conv3_7" 570 | top: "res3_7" 571 | eltwise_param { 572 | operation: 1 573 | } 574 | } 575 | layer { 576 | name: "conv3_8" 577 | type: "Convolution" 578 | bottom: "res3_7" 579 | top: "conv3_8" 580 | param { 581 | lr_mult: 1 582 | decay_mult: 1 583 | } 584 | param { 585 | lr_mult: 0 586 | decay_mult: 0 587 | } 588 | convolution_param { 589 | num_output: 256 590 | kernel_size: 3 591 | stride: 1 592 | pad: 1 593 | weight_filler { 594 | type: "gaussian" 595 | std: 0.01 596 | } 597 | bias_filler { 598 | type: "constant" 599 | value: 0 600 | } 601 | } 602 | } 603 | layer { 604 | name: "relu3_8" 605 | type: "PReLU" 606 | bottom: "conv3_8" 607 | top: "conv3_8" 608 | } 609 | layer { 610 | name: "conv3_9" 611 | type: "Convolution" 612 | bottom: "conv3_8" 613 | top: "conv3_9" 614 | param { 615 | lr_mult: 1 616 | decay_mult: 1 617 | } 618 | param { 619 | lr_mult: 0 620 | decay_mult: 0 621 | } 622 | convolution_param { 623 | num_output: 256 624 | kernel_size: 3 625 | stride: 1 626 | pad: 1 627 | weight_filler { 628 | type: "gaussian" 629 | std: 0.01 630 | } 631 | bias_filler { 632 | type: "constant" 633 | value: 0 634 | } 635 | } 636 | } 637 | layer { 638 | name: "relu3_9" 639 | type: "PReLU" 640 | bottom: "conv3_9" 641 | top: "conv3_9" 642 | } 643 | layer { 644 | name: "res3_9" 645 | type: "Eltwise" 646 | bottom: "res3_7" 647 | bottom: "conv3_9" 648 | top: "res3_9" 649 | eltwise_param { 650 | operation: 1 651 | } 652 | } 653 | layer { 654 | name: "conv4_1" 655 | type: "Convolution" 656 | bottom: "res3_9" 657 | top: "conv4_1" 658 | param { 659 | lr_mult: 1 660 | decay_mult: 1 661 | } 662 | param { 663 | lr_mult: 2 664 | decay_mult: 0 665 | } 666 | convolution_param { 667 | num_output: 512 668 | kernel_size: 3 669 | stride: 2 670 | pad: 1 671 | weight_filler { 672 | type: "xavier" 673 | } 674 | bias_filler { 675 | type: "constant" 676 | value: 0 677 | } 678 | } 679 | } 680 | layer { 681 | name: "relu4_1" 682 | type: "PReLU" 683 | bottom: "conv4_1" 684 | top: "conv4_1" 685 | } 686 | layer { 687 | name: "conv4_2" 688 | type: "Convolution" 689 | bottom: "conv4_1" 690 | top: "conv4_2" 691 | param { 692 | lr_mult: 1 693 | decay_mult: 1 694 | } 695 | param { 696 | lr_mult: 0 697 | decay_mult: 0 698 | } 699 | convolution_param { 700 | num_output: 512 701 | kernel_size: 3 702 | stride: 1 703 | pad: 1 704 | weight_filler { 705 | type: "gaussian" 706 | std: 0.01 707 | } 708 | bias_filler { 709 | type: "constant" 710 | value: 0 711 | } 712 | } 713 | } 714 | layer { 715 | name: "relu4_2" 716 | type: "PReLU" 717 | bottom: "conv4_2" 718 | top: "conv4_2" 719 | } 720 | layer { 721 | name: "conv4_3" 722 | type: "Convolution" 723 | bottom: "conv4_2" 724 | top: "conv4_3" 725 | param { 726 | lr_mult: 1 727 | decay_mult: 1 728 | } 729 | param { 730 | lr_mult: 0 731 | decay_mult: 0 732 | } 733 | convolution_param { 734 | num_output: 512 735 | kernel_size: 3 736 | stride: 1 737 | pad: 1 738 | weight_filler { 739 | type: "gaussian" 740 | std: 0.01 741 | } 742 | bias_filler { 743 | type: "constant" 744 | value: 0 745 | } 746 | } 747 | } 748 | layer { 749 | name: "relu4_3" 750 | type: "PReLU" 751 | bottom: "conv4_3" 752 | top: "conv4_3" 753 | } 754 | layer { 755 | name: "res4_3" 756 | type: "Eltwise" 757 | bottom: "conv4_1" 758 | bottom: "conv4_3" 759 | top: "res4_3" 760 | eltwise_param { 761 | operation: 1 762 | } 763 | } 764 | layer { 765 | name: "fc5" 766 | type: "InnerProduct" 767 | bottom: "res4_3" 768 | top: "fc5" 769 | param { 770 | lr_mult: 1 771 | decay_mult: 1 772 | } 773 | param { 774 | lr_mult: 2 775 | decay_mult: 0 776 | } 777 | inner_product_param { 778 | num_output: 512 779 | weight_filler { 780 | type: "xavier" 781 | } 782 | bias_filler { 783 | type: "constant" 784 | value: 0 785 | } 786 | } 787 | } -------------------------------------------------------------------------------- /LFW/plot.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import random 3 | import os 4 | 5 | def getPlotColor(i): 6 | cnames = [ 7 | '#ED1F24', 8 | '#B8529F', 9 | '#3952A3', 10 | '#69BC45', 11 | '#FF8400', 12 | '#A74E44', 13 | '#7642CC', 14 | '#000000', 15 | '#00FF00', 16 | '#FF0000'] 17 | return cnames[i % 10] 18 | 19 | def draw_chart(log_name, path_to_png, maps, precision, threshold): 20 | line_width = 1.0 # the line width 21 | # plot 22 | figure_1 = plt.figure(log_name,figsize=(12, 6)) 23 | ax= plt.subplot(1,1,1) 24 | ax.grid(True,color="gray",linestyle="-." ) 25 | max_size = 0 26 | for name in maps: 27 | y = maps[name] 28 | max_size = max(max_size, len(y)) 29 | idx = 0 30 | for name in maps: 31 | y = maps[name] 32 | #print(y) 33 | n = len(y) 34 | if n < max_size * 0.2: 35 | continue 36 | 37 | x = [i for i in range(0,n)] 38 | ave = float(sum(y))/n 39 | label = '%.1f %s' % (ave, name) 40 | # ema 41 | c = getPlotColor(idx) 42 | plt.plot(x , y, color=c, linewidth=line_width,label = label) 43 | idx += 1 44 | # threshold line 45 | label = 'threshold:%.4f' % (threshold) 46 | plt.plot([0, max_size], [threshold,threshold], color='green', linewidth=line_width,label = label) 47 | plt.title('%.4f -- %s' % (precision, log_name)) 48 | plt.xlabel('x') 49 | plt.ylabel('y') 50 | plt.legend(loc='lower left') 51 | png_path = os.path.join(path_to_png, '%.4f--%s.png'%(precision, log_name)) 52 | plt.savefig(png_path) -------------------------------------------------------------------------------- /LFW/run_verify.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | from __future__ import print_function 3 | import math 4 | import numpy as np 5 | import logging 6 | import time 7 | import os 8 | import pickle 9 | import argparse 10 | import cv2 11 | 12 | from verification import verification 13 | from plot import draw_chart 14 | 15 | import sys 16 | sys.path.insert(0, '../facealign') 17 | sys.path.insert(0, '../util') 18 | 19 | from caffe_extractor import CaffeExtractor 20 | from distance import get_distance 21 | 22 | def parse_line(line): 23 | splits = line.split() 24 | # skip line 25 | if len(splits) < 3: 26 | return None 27 | # name id1 id2 28 | if len(splits) == 3: 29 | return True, splits[0], splits[1], splits[0], splits[2] 30 | # name1 id1 name2 id2 31 | return False, splits[0], splits[1], splits[2], splits[3] 32 | 33 | def load_image_list(pair_list): 34 | img_list = [] 35 | for pair in pair_list: 36 | # skip invalid pairs 37 | if not os.path.exists(pair[0]) or not os.path.exists(pair[1]): 38 | continue 39 | img1 = cv2.imread(pair[0]) 40 | #img1 = cv2.cvtColor(img1, cv2.COLOR_RGB2BGR) 41 | img2 = cv2.imread(pair[1]) 42 | #img2 = cv2.cvtColor(img2, cv2.COLOR_RGB2BGR) 43 | #print(img1.shape) 44 | img_list.append([img1, img2, pair[0], pair[1]]) 45 | return img_list 46 | 47 | def load_ytf_pairs(path, prefix): 48 | pos_list_ = [] 49 | neg_list_ = [] 50 | with open(path, 'r') as f: 51 | for line in f.readlines(): 52 | line = line.strip() 53 | flag, a, b = line.split(',') 54 | flag = int(flag) 55 | a = os.path.join(prefix, a) 56 | b = os.path.join(prefix, b) 57 | if flag == 1: 58 | pos_list_.append([a, b]) 59 | else: 60 | neg_list_.append([a, b]) 61 | 62 | pos_img = load_image_list(pos_list_) 63 | neg_img = load_image_list(neg_list_) 64 | return pos_img, neg_img 65 | 66 | 67 | def load_image_paris(pair_path, prefix): 68 | pair_list = [] 69 | # parse pairs 70 | with open(pair_path, 'r') as f: 71 | for line in f.readlines(): 72 | pair = parse_line(line) 73 | if pair is not None: 74 | pair_list.append(pair) 75 | # print(pair) 76 | #print('#pairs:%d' % len(pair_list)) 77 | # compute feature 78 | pos_img = [] 79 | neg_img = [] 80 | count = 0 81 | for pair in pair_list: 82 | count += 1 83 | 84 | img_path1 = '%s/%s/%s_%04d.jpg' % (prefix, pair[1], pair[1], int(pair[2])) 85 | img_path2 = '%s/%s/%s_%04d.jpg' % (prefix, pair[3], pair[3], int(pair[4])) 86 | rel_path1 = '%s/%s_%04d.jpg' % (pair[1], pair[1], int(pair[2])) 87 | rel_path2 = '%s/%s_%04d.jpg' % (pair[3], pair[3], int(pair[4])) 88 | # skip invalid pairs 89 | if not os.path.exists(img_path1) or not os.path.exists(img_path2): 90 | continue 91 | img1 = cv2.imread(img_path1) 92 | #img1 = cv2.cvtColor(img1, cv2.COLOR_RGB2BGR) 93 | img2 = cv2.imread(img_path2) 94 | #img2 = cv2.cvtColor(img2, cv2.COLOR_RGB2BGR) 95 | #print(img1.shape) 96 | if pair[0]: 97 | pos_img.append([img1, img2, rel_path1, rel_path2]) 98 | else: 99 | neg_img.append([img1, img2, rel_path1, rel_path2]) 100 | return pos_img, neg_img 101 | 102 | 103 | def extract_feature(extractor, img_list): 104 | feat_list = [] 105 | n = len(img_list) 106 | idx = 1 107 | for pair in img_list: 108 | img1 = pair[0] 109 | img2 = pair[1] 110 | feat1 = extractor.extract_feature(img1) 111 | feat2 = extractor.extract_feature(img2) 112 | feat_list.append([feat1, feat2]) 113 | if idx > 1: 114 | print('{}'.format('\b'*10)) 115 | print('{}/{}'.format(idx, n), end='') 116 | idx += 1 117 | return feat_list 118 | 119 | def crop_image_list(img_list, imsize): 120 | out_list = [] 121 | h, w, c = img_list[0][0].shape 122 | x1 = (w - imsize[0])/2 123 | y1 = (h - imsize[1])/2 124 | for pair in img_list: 125 | img1 = pair[0] 126 | img2 = pair[1] 127 | img1 = img1[y1:(y1+imsize[1]),x1:(x1+imsize[0]),:] 128 | img2 = img2[y1:(y1+imsize[1]),x1:(x1+imsize[0]),:] 129 | out_list.append([img1, img2]) 130 | #print(img1.shape) 131 | return out_list 132 | 133 | 134 | def load_bin(path, image_size): 135 | import mxnet as mx 136 | bins, issame_list = pickle.load(open(path, 'rb')) 137 | pos_img = [] 138 | neg_img = [] 139 | for i in xrange(len(issame_list)): 140 | _bin = bins[i*2] 141 | img1 = mx.image.imdecode(_bin) 142 | _bin = bins[i*2+1] 143 | img2 = mx.image.imdecode(_bin) 144 | if issame_list[i]: 145 | pos_img.append([img1, img2]) 146 | else: 147 | neg_img.append([img2, img2]) 148 | return pos_img, neg_img 149 | 150 | 151 | def model_centerface(do_mirror): 152 | model_dir = './models/centerface/' 153 | model_proto = model_dir + 'face_deploy.prototxt' 154 | model_path = model_dir + 'face_model.caffemodel' 155 | image_size = (96, 112) 156 | extractor = CaffeExtractor(model_proto, model_path, do_mirror = do_mirror, featLayer='fc5') 157 | return extractor, image_size 158 | 159 | def model_sphereface(do_mirror): 160 | model_dir = './models/sphereface/' 161 | model_proto = model_dir + 'sphereface_deploy.prototxt' 162 | model_path = model_dir + 'sphereface_model.caffemodel' 163 | image_size = (96, 112) 164 | extractor = CaffeExtractor(model_proto, model_path, do_mirror = do_mirror, featLayer='fc5') 165 | return extractor, image_size 166 | 167 | def model_AMSoftmax(do_mirror): 168 | model_dir = './models/AMSoftmax/' 169 | if do_mirror: 170 | model_proto = model_dir + 'face_deploy_mirror_normalize.prototxt' 171 | else: 172 | model_proto = model_dir + 'deploy.prototxt' 173 | model_path = model_dir + 'face_train_test_iter_30000.caffemodel' 174 | image_size = (96, 112) 175 | extractor = CaffeExtractor(model_proto, model_path, do_mirror = False, featLayer='fc5') 176 | return extractor, image_size 177 | 178 | 179 | def model_arcface(do_mirror): 180 | model_dir = './models/arcface/' 181 | model_proto = model_dir + 'model.prototxt' 182 | model_path = model_dir + 'model-r50-am.caffemodel' 183 | image_size = (112, 112) 184 | extractor = CaffeExtractor(model_proto, model_path, do_mirror = do_mirror, featLayer='fc1') 185 | return extractor, image_size 186 | 187 | 188 | def model_mobileface(do_mirror): 189 | model_dir = './models/mobilefacenet/' 190 | model_proto = model_dir + 'mobilefacenet-res2-6-10-2-dim128-opencv.prototxt' 191 | model_path = model_dir + 'mobilefacenet-res2-6-10-2-dim128.caffemodel' 192 | image_size = (112, 112) 193 | extractor = CaffeExtractor(model_proto, model_path, do_mirror = do_mirror, featLayer='fc1') 194 | return extractor, image_size 195 | 196 | 197 | def model_yours(do_mirror): 198 | model_dir = '/path/to/your/model/' 199 | model_proto = model_dir + 'deploy.prototxt' 200 | model_path = model_dir + 'weights.caffemodel' 201 | image_size = (112, 112) 202 | extractor = CaffeExtractor(model_proto, model_path, do_mirror = do_mirror, featLayer='fc5') 203 | return extractor, image_size 204 | 205 | 206 | def model_factory(name, do_mirror): 207 | model_dict = { 208 | 'centerface':model_centerface, 209 | 'sphereface':model_sphereface, 210 | 'AMSoftmax' :model_AMSoftmax, 211 | 'arcface' :model_arcface, 212 | 'mobileface':model_mobileface, 213 | 'yours' :model_yours, 214 | } 215 | model_func = model_dict[name] 216 | return model_func(do_mirror) 217 | 218 | 219 | if __name__ == '__main__': 220 | parser = argparse.ArgumentParser() 221 | parser.add_argument("--test_set", help="lfw | ytf") 222 | parser.add_argument("--data", help="lfw.np or pair.txt") 223 | parser.add_argument("--prefix", help="data prefix") 224 | parser.add_argument("--model_name", help= 'specify which model to test \n' 225 | ' centerface\n' 226 | ' sphereface\n' 227 | ' AMSoftmax\n' 228 | ' arcface\n' 229 | ' yours \n') 230 | parser.add_argument("--dist_type", default='cosine', help="distance measure ['cosine', 'L2', 'SSD']") 231 | parser.add_argument("--do_mirror", default=False, help="mirror image and concatinate features") 232 | 233 | args = parser.parse_args() 234 | output_dir = '.' 235 | # parse args 236 | model_name = args.model_name 237 | test_set = args.test_set 238 | dist_type = args.dist_type 239 | do_mirror = args.do_mirror 240 | print('Dataset \t: %s (%s,%s)' % (args.test_set, args.data, args.prefix)) 241 | print('Testing \t: %s' % model_name) 242 | print('Distance \t: %s' % dist_type) 243 | print('Do mirror\t: {}'.format(do_mirror)) 244 | # model 245 | extractor, image_size = model_factory(model_name, do_mirror) 246 | print('Testing model\t: %s' % (extractor.weight)) 247 | print('Image size\t: {}'.format(image_size)) 248 | # load images 249 | if args.data.find('.np') > 0: 250 | pos_img, neg_img = pickle.load(open(args.data, 'rb')) 251 | #pos_img, neg_img = pickle.load(open(lfw_data, 'rb'), encoding='iso-8859-1') 252 | else: 253 | if args.test_set == 'lfw': 254 | pos_img, neg_img = load_image_paris(args.data, args.prefix) 255 | else: 256 | pos_img, neg_img = load_ytf_pairs(args.data, args.prefix) 257 | 258 | # crop image 259 | pos_img = crop_image_list(pos_img, image_size) 260 | neg_img = crop_image_list(neg_img, image_size) 261 | #print(type(pos_img[0][0])) 262 | #exit() 263 | # compute feature 264 | print('Extracting features ...') 265 | pos_list = extract_feature(extractor, pos_img) 266 | print(' Done positive pairs') 267 | neg_list = extract_feature(extractor, neg_img) 268 | print(' Done negative pairs') 269 | 270 | # evaluate 271 | print('Evaluating ...') 272 | precision, std, threshold, pos, neg = verification(pos_list, neg_list, dist_type = dist_type) 273 | _, title = os.path.split(extractor.weight) 274 | #draw_chart(title, output_dir, {'pos': pos, 'neg': neg}, precision, threshold) 275 | print('------------------------------------------------------------') 276 | print('Precision on %s : %1.5f+-%1.5f \nBest threshold : %f' % (args.test_set, precision, std, threshold)) 277 | 278 | 279 | 280 | -------------------------------------------------------------------------------- /LFW/test_lfw.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | import os,sys 3 | import math 4 | 5 | sys.path.insert(0, '../util') 6 | 7 | from caffe_extractor import CaffeExtractor 8 | from distance import get_distance 9 | 10 | import numpy as np 11 | import argparse 12 | 13 | 14 | LFW_PAIRS = None 15 | LFW_IMG_DIR = None 16 | 17 | def parse_line(line): 18 | splits = line.split() 19 | # skip line 20 | if len(splits) < 3: 21 | return None 22 | # name id1 id2 23 | if len(splits) == 3: 24 | return True, splits[0], splits[1], splits[0], splits[2] 25 | # name1 id1 name2 id2 26 | return False, splits[0], splits[1], splits[2], splits[3] 27 | 28 | 29 | def find_threshold_sort(pos_list,neg_list): 30 | pos_list = sorted(pos_list, key=lambda x: x[0]) 31 | neg_list = sorted(neg_list, key=lambda x: x[0], reverse=True) 32 | pos_count = len(pos_list) 33 | neg_count = len(neg_list) 34 | correct = 0 35 | threshold = 0 36 | for i in range(min(pos_count, neg_count)): 37 | if pos_list[i][0] > neg_list[i][0]: 38 | correct = i 39 | threshold = (pos_list[i][0] + neg_list[i][0])/2 40 | break 41 | precision = (correct * 2.0) / (pos_count + neg_count) 42 | return precision, threshold 43 | 44 | 45 | def get_accuracy(pos_list,neg_list,threshold): 46 | pos_count = len(pos_list) 47 | neg_count = len(neg_list) 48 | correct = 0 49 | for i in range(pos_count): 50 | if pos_list[i][0] < threshold: 51 | correct += 1 52 | 53 | for i in range(neg_count): 54 | if neg_list[i][0] > threshold: 55 | correct += 1 56 | precision = float(correct) / (pos_count + neg_count) 57 | return precision 58 | 59 | 60 | def best_threshold(pos_list, neg_list, thrNum = 10000): 61 | ts = np.linspace(-1, 1, thrNum*2+1) 62 | best_acc = 0 63 | best_t = 0 64 | for t in ts: 65 | acc = get_accuracy(pos_list, neg_list, t) 66 | if acc > best_acc: 67 | best_acc = acc 68 | best_t = t 69 | return best_acc, best_t 70 | 71 | 72 | def test_kfold(pos_list, neg_list, k = 10): 73 | fold_size = len(pos_list)/k 74 | sum_acc = 0 75 | sum_thresh = 0 76 | sum_n = 0 77 | for i in range(k): 78 | val_pos = [] 79 | val_neg = [] 80 | test_pos = [] 81 | test_neg = [] 82 | for j in range(len(pos_list)): 83 | fi = j/fold_size 84 | if fi != i: 85 | val_pos.append(pos_list[j]) 86 | val_neg.append(neg_list[j]) 87 | else: 88 | test_pos.append(pos_list[j]) 89 | test_neg.append(neg_list[j]) 90 | precision, threshold = find_threshold_sort(val_pos, val_neg) 91 | accuracy = get_accuracy(test_pos, test_neg, threshold) 92 | sum_acc += accuracy 93 | sum_thresh += threshold 94 | sum_n += 1 95 | # verbose 96 | print('precision:%.4f threshold:%f' % (accuracy, threshold)) 97 | return sum_acc/sum_n, sum_thresh/sum_n 98 | 99 | 100 | def parse_pair_file(pair_path, prefix, feat_extractor,dist_func): 101 | pair_list = [] 102 | # parse pairs 103 | with open(pair_path, 'r') as f: 104 | for line in f.readlines(): 105 | pair = parse_line(line) 106 | if pair is not None: 107 | pair_list.append(pair) 108 | # print(pair) 109 | print('#pairs:%d' % len(pair_list)) 110 | # compute feature 111 | pos_list = [] 112 | neg_list = [] 113 | count = 0 114 | features = [] 115 | for pair in pair_list: 116 | count += 1 117 | img_path1 = '%s/%s/%s_%04d.jpg' % (prefix, pair[1], pair[1], int(pair[2])) 118 | img_path2 = '%s/%s/%s_%04d.jpg' % (prefix, pair[3], pair[3], int(pair[4])) 119 | # skip invalid pairs 120 | if not os.path.exists(img_path1) or not os.path.exists(img_path2): 121 | continue 122 | feat1 = feat_extractor.extract(img_path1) 123 | feat2 = feat_extractor.extract(img_path2) 124 | dist = dist_func(feat1, feat2) 125 | if count % 100 == 1: 126 | print('%4d dist:%.4f %s |1|:%.4f |2|:%.4f' % (count, dist, pair[0], 127 | np.sqrt(np.sum(np.square(feat1))), np.sqrt(np.sum(np.square(feat2))))) 128 | 129 | if pair[0]: 130 | pos_list.append([dist, feat1, feat2, img_path1, img_path2]) 131 | else: 132 | neg_list.append([dist, feat1, feat2, img_path1, img_path2]) 133 | features.append(feat1) 134 | features.append(feat2) 135 | 136 | # find best threshold() 137 | #precision, threshold = best_threshold(pos_list, neg_list, 10000) 138 | #return precision, threshold, pos_list, neg_list 139 | precision, threshold = test_kfold(pos_list, neg_list) 140 | return precision, threshold, pos_list, neg_list 141 | 142 | def test_loss(extractor, weight, dist_type): 143 | dist_func = get_distance(dist_type) 144 | global LFW_PAIRS 145 | global LFW_IMG_DIR 146 | dir, path = os.path.split(weight) 147 | fnames = os.listdir(dir) 148 | fpattern = '%s.%s' % (path,dist_type) 149 | existed = False 150 | for fname in fnames: 151 | if fname.startswith(fpattern): 152 | existed = True 153 | print('skip:%s ' % (weight)) 154 | return 155 | 156 | print('test:%s ' % (weight)) 157 | # test 158 | precision, threshold, pos_list, neg_list = parse_pair_file(LFW_PAIRS, LFW_IMG_DIR, extractor,dist_func) 159 | print('precision on lfw:%.4f threshold:%f ' % (precision, threshold)) 160 | filename = '.%s.%.2f.txt' % (dist_type, precision*100) 161 | # write result 162 | with open(weight+filename,'w') as f: 163 | f.write( 'precision on lfw:%.4f threshold:%f ' % (precision, threshold) ) 164 | 165 | 166 | def test_model(model, weight,dist_type='cosine',do_mirror=False, feat_layer='fc5'): 167 | extractor = CaffeExtractor(model, weight,do_mirror=do_mirror, featLayer=feat_layer ) 168 | test_loss(extractor, weight, dist_type) 169 | #test_loss(extractor, weight, 'SSD') 170 | 171 | def test_dir(model_dir,dist_type='cosine',do_mirror=False): 172 | filenames = os.listdir(model_dir) 173 | for filename in filenames: 174 | ext = os.path.splitext(filename)[1] 175 | if ext != '.caffemodel': 176 | continue 177 | # test the model 178 | model_path = os.path.join(model_dir, filename) 179 | test_model(model_dir+'/deploy.prototxt',model_path,dist_type,do_mirror) 180 | 181 | if __name__ == '__main__': 182 | parser = argparse.ArgumentParser() 183 | parser.add_argument("--lfw_dir", help="lfw image dir") 184 | parser.add_argument("--lfw_pair", help="lfw pair file") 185 | parser.add_argument("--model", help="model prototxt OR dir") 186 | parser.add_argument("--weights", help="model weights") 187 | parser.add_argument("--feat_layer", help="fc5") 188 | parser.add_argument("-t", "--dist_type", default='cosine', help="distance measure ['cosine', 'L2', 'SSD']") 189 | parser.add_argument("-f", "--do_mirror", default=False,help="mirror image and concatinate features") 190 | 191 | args = parser.parse_args() 192 | print(args) 193 | LFW_PAIRS = args.lfw_pair 194 | LFW_IMG_DIR = args.lfw_dir 195 | 196 | if args.weights: 197 | test_model(args.model,args.weights,args.dist_type,args.do_mirror) 198 | else: 199 | test_dir(args.model,args.dist_type,args.do_mirror) 200 | 201 | -------------------------------------------------------------------------------- /LFW/verification.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | import os,sys 3 | import math 4 | import numpy as np 5 | import argparse 6 | 7 | sys.path.insert(0, '../..') 8 | sys.path.insert(0, '../util') 9 | 10 | from distance import get_distance 11 | 12 | 13 | def find_threshold_sort(pos,neg): 14 | pos_list = sorted(pos, key=lambda x: x[0]) 15 | neg_list = sorted(neg, key=lambda x: x[0], reverse=True) 16 | pos_count = len(pos_list) 17 | neg_count = len(neg_list) 18 | correct = 0 19 | threshold = 0 20 | #print('sort pos') 21 | #print(pos_list) 22 | #print('sort neg') 23 | #print(neg_list) 24 | for i in range(min(pos_count, neg_count)): 25 | if pos_list[i][0] > neg_list[i][0]: 26 | correct = i 27 | threshold = (pos_list[i][0] + neg_list[i][0])/2 28 | break 29 | #print("%d/%d" % (correct, pos_count)) 30 | precision = (correct * 2.0) / (pos_count + neg_count) 31 | return precision, threshold 32 | 33 | 34 | def get_accuracy(pos_list,neg_list,threshold): 35 | pos_count = len(pos_list) 36 | neg_count = len(neg_list) 37 | correct = 0 38 | for i in range(pos_count): 39 | if pos_list[i][0] < threshold: 40 | correct += 1 41 | 42 | for i in range(neg_count): 43 | if neg_list[i][0] > threshold: 44 | correct += 1 45 | precision = float(correct) / (pos_count + neg_count) 46 | return precision 47 | 48 | 49 | def best_threshold(pos_list, neg_list, thrNum = 10000): 50 | ts = np.linspace(-1, 1, thrNum*2+1) 51 | best_acc = 0 52 | best_t = 0 53 | for t in ts: 54 | acc = get_accuracy(pos_list, neg_list, t) 55 | if acc > best_acc: 56 | best_acc = acc 57 | best_t = t 58 | return best_acc, best_t 59 | 60 | 61 | def test_kfold(pos_list, neg_list, k = 10): 62 | fold_size = len(pos_list)//k 63 | sum_acc = 0 64 | sum_thresh = 0 65 | sum_n = 0 66 | accu_list = [] 67 | for i in range(k): 68 | val_pos = [] 69 | val_neg = [] 70 | test_pos = [] 71 | test_neg = [] 72 | for j in range(len(pos_list)): 73 | fi = j//fold_size 74 | if fi != i: 75 | val_pos.append(pos_list[j]) 76 | val_neg.append(neg_list[j]) 77 | else: 78 | test_pos.append(pos_list[j]) 79 | test_neg.append(neg_list[j]) 80 | precision, threshold = find_threshold_sort(val_pos, val_neg) 81 | accuracy = get_accuracy(test_pos, test_neg, threshold) 82 | accu_list.append(accuracy) 83 | sum_acc += accuracy 84 | sum_thresh += threshold 85 | sum_n += 1 86 | # verbose 87 | print('precision:%.4f threshold:%f' % (accuracy, threshold)) 88 | return sum_acc/sum_n, sum_thresh/sum_n, accu_list 89 | 90 | 91 | def verification(pos_list, neg_list, dist_type = 'L2'): 92 | ''' 93 | [ 94 | [feat1, feat2, ..], 95 | ... 96 | [feat1, feat2, ..] 97 | ] 98 | ''' 99 | # distance measure 100 | if isinstance(dist_type, str): 101 | dist_func = get_distance(dist_type) 102 | else: 103 | dist_func = dist_type 104 | # get dist 105 | pos_dist = [] 106 | for i in pos_list: 107 | dist = dist_func(i[0], i[1]) 108 | diff = i[0] - i[1] 109 | pos_dist.append([dist]) 110 | 111 | neg_dist = [] 112 | for i in neg_list: 113 | dist = dist_func(i[0], i[1]) 114 | neg_dist.append([dist]) 115 | precision, threshold, accu_list = test_kfold(pos_dist, neg_dist) 116 | pos = sorted(pos_dist, key=lambda x: x[0]) 117 | neg = sorted(neg_dist, key=lambda x: x[0], reverse=True) 118 | pos = [x[0] for x in pos] 119 | neg = [x[0] for x in neg] 120 | acc, std = np.mean(accu_list), np.std(accu_list) 121 | return acc, std, threshold, pos, neg 122 | 123 | 124 | -------------------------------------------------------------------------------- /Megaface/README.md: -------------------------------------------------------------------------------- 1 | # MegaFace 2 | 3 | Some script for the [MegaFace](http://megaface.cs.washington.edu) Test. 4 | 5 | # Alignment 6 | 7 | ## Facescrub 8 | 9 | ``` 10 | python align_facescrub.py facescrub_image_dir aligned_dir features_list_json_path 11 | ``` 12 | This will do alignment using the *correct* landmarks in the file 'facescrub_80_landmark5.json' 13 | ## MegaFace 14 | 15 | python align_megaface.py megaface_image_dir aligned_dir distractor_templatelists_dir 16 | 17 | 18 | # Extract feature(with PyCaffe) 19 | 20 | ## Setup 21 | 22 | Copy the `config.conf.example` file `config.conf` and modify the paths to fit your environment. 23 | 24 | ## Run 25 | 26 | You can write more than one models in config.conf, and choose the model in the section `[model].name` field or specify it in command parameters. 27 | 28 | python extract_feature_list.py config.conf [model_name] 29 | # Testing 30 | 31 | ## Run test 32 | 33 | A simplified Rank-1 test for debugging purpose. 34 | 35 | python run_test.py config_file distractors 36 | 37 | ## Plot 38 | 39 | Plot the results of the MegaFace devkit outputs 40 | 41 | python plot.py result_json -------------------------------------------------------------------------------- /Megaface/align_facescrub.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | import cv2 4 | import os,sys 5 | import time 6 | import os.path 7 | import math 8 | sys.path.insert(0, '../facealign') 9 | sys.path.insert(0, '../util') 10 | 11 | from fileutil import * 12 | from MtcnnPycaffe import MtcnnDetector, draw_and_show 13 | from alignment import * 14 | from logfile import * 15 | 16 | import json 17 | import argparse 18 | 19 | def IoU(bbox1, bbox2): 20 | intersect_bbox = [max(bbox1[0], bbox2[0]), max(bbox1[1], bbox2[1]), 21 | min(bbox1[0]+bbox1[2], bbox2[0]+bbox2[2]), min(bbox1[1]+bbox1[3], bbox2[1]+bbox2[3])] 22 | overlap = (intersect_bbox[2] - intersect_bbox[0]) * (intersect_bbox[3] - intersect_bbox[1]) 23 | overlap_rate = overlap / (bbox1[2]*bbox1[3] + bbox2[2]*bbox2[3] - overlap) 24 | return overlap_rate 25 | 26 | 27 | def load_bbox_file(path, dict): 28 | lines = read_lines(path) 29 | # skip first 30 | for i in range(1,len(lines)): 31 | line = lines[i] 32 | segs = line.split('\t') 33 | name = segs[0] 34 | face_id = segs[2] 35 | bbox = segs[4] 36 | vals = bbox.split(',') 37 | x0 = int(vals[0]) 38 | y0 = int(vals[1]) 39 | x1 = int(vals[2]) 40 | y1 = int(vals[3]) 41 | rect = [x0,y0,x1 - x0, y1 - y0] 42 | # name_faceid 43 | key = name + '_' + face_id 44 | dict[key] = rect 45 | 46 | return dict 47 | 48 | class FacescrubAlignVisitor(object): 49 | """ 50 | Megaface alignment 51 | """ 52 | def __init__(self, 53 | src_prefix, 54 | dst_prefix, 55 | detector, 56 | bbox, 57 | skip_exist = False, 58 | transform = 'sililarity', 59 | pading = 0): 60 | 61 | self.src_prefix = src_prefix 62 | self.dst_prefix = dst_prefix 63 | self.skip_exist = skip_exist 64 | self.detector = detector 65 | self.bbox = bbox 66 | self.transform = transform 67 | self.pading = pading 68 | # statistic 69 | self.done_count = 0 70 | self.fail_count = 0 71 | 72 | def process(self, path): 73 | if not is_image_file(path): 74 | return True 75 | 76 | dst_path = translate_path(self.src_prefix, self.dst_prefix, path) 77 | 78 | if self.skip_exist and os.path.exists(dst_path): 79 | # print('skip:%s' % path) 80 | return True 81 | #print('%s -> %s' % (path, dst_path)) 82 | img = cv2_imread(path) 83 | if img is None: 84 | print('load error:%s'%(path)) 85 | log_write(path) 86 | self.fail_count += 1 87 | return False 88 | 89 | #print('run:%s/%s'%(subdir,filename)) 90 | try: 91 | boxes, points = self.detector.detect_face(img) 92 | except: 93 | print('detect error:%s'%(path)) 94 | log_write(path) 95 | self.fail_count += 1 96 | return False 97 | if points is None or len(points) == 0: 98 | log_write(path) 99 | self.fail_count += 1 100 | return False 101 | 102 | # find the one largest IoU 103 | dir, fname = os.path.split(path) 104 | key, _ = os.path.splitext(fname) 105 | target_box = self.bbox[key] 106 | max_idx = 0 107 | max_iou = 0 108 | for i, box in enumerate(boxes): 109 | box = [box[0], box[1], box[2] - box[0], box[3] - box[1]] 110 | iou = IoU(box, target_box) 111 | if iou > max_iou: 112 | max_iou = iou 113 | max_idx = i 114 | # check iou 115 | if max_iou < 0.3: 116 | #cv2.rectangle(img, (target_box[0],target_box[1]), 117 | # (target_box[0] + target_box[2], target_box[1] + target_box[3]), (0,255,0), 2) 118 | #draw_and_show(img, boxes, points ) 119 | #ch = cv2.waitKey(0) 120 | ch = 0 121 | if ch == 27: 122 | log_write(path) 123 | self.fail_count += 1 124 | return False 125 | 126 | max_chip = align_to_96x112(img, points[max_idx], self.pading, trans_type = self.transform) 127 | #draw_and_show(img,boxes, points ) 128 | #cv2.imshow('chip', max_chip) 129 | #cv2.waitKey(0) 130 | makedirs(dst_path) 131 | ret = cv2_imwrite(dst_path, max_chip) 132 | if ret == False: 133 | print('imwrite error:%s'%(path)) 134 | log_write(path) 135 | self.fail_count += 1 136 | return False 137 | 138 | # report 139 | if self.done_count % 100 == 0: 140 | print('done:%05d, fail:%05d img:%s'%(self.done_count, self.fail_count, path)) 141 | 142 | self.done_count += 1 143 | return True 144 | 145 | def align_facescrub_uncropped(src_dir, dst_dir, templatelists_path, dict, gpu_id = 0): 146 | # load json 147 | with open(templatelists_path, 'r') as f: 148 | data = json.load(f) 149 | rel_list = data['path'] 150 | 151 | # to fullpath 152 | path_list = [ os.path.join(src_dir,p) for p in rel_list ] 153 | # init detector 154 | detector = MtcnnDetector( minsize=36, gpu_id = gpu_id ) 155 | # align by detection 156 | visitor = FacescrubAlignVisitor(src_dir,dst_dir,detector, dict) 157 | detect_fail_list = templatelists_path + '.detect-fail.txt' 158 | log_open(detect_fail_list) 159 | total_size = len(path_list) 160 | for i in range(total_size): 161 | path = path_list[i] 162 | #print('%d/%d %s' % (i,total_size,path)) 163 | visitor.process(path) 164 | log_close() 165 | 166 | 167 | def align_facescrub_fail(src_dir, dst_dir, templatelists_path, dict, gpu_id = 0): 168 | # init detector 169 | detector = MtcnnDetector( minsize=36, gpu_id = gpu_id ) 170 | # align by detection 171 | visitor = FacescrubAlignVisitor(src_dir,dst_dir,detector, dict) 172 | detect_fail_list = templatelists_path + '.detect-fail.txt' 173 | log_open(templatelists_path + '.final-fail.txt') 174 | list_walker(detect_fail_list,visitor) 175 | log_close() 176 | 177 | def align_facescrub_fail_json(src_dir, dst_dir, templatelists_path, dict, json_path): 178 | # load json 179 | with open(json_path, 'r') as f: 180 | data = json.load(f) 181 | print(data) 182 | list = read_lines(templatelists_path + '.final-fail.txt') 183 | for path in list: 184 | dst_path = translate_path(src_dir, dst_dir, path) 185 | dir, fname = os.path.split(path) 186 | key, _ = os.path.splitext(fname) 187 | print(key) 188 | target_box = dict[key] 189 | img = cv2_imread(path) 190 | point = data[key] 191 | xxyy = [] 192 | for i in range(5): 193 | xxyy.append(point[i*2]) 194 | for i in range(5): 195 | xxyy.append(point[i*2+1]) 196 | print(xxyy) 197 | max_chip = align_to_96x112(img, xxyy) 198 | makedirs(dst_path) 199 | cv2_imwrite(dst_path, max_chip) 200 | #draw_and_show(img, [target_box], [xxyy] ) 201 | #ch = cv2.waitKey(0) 202 | 203 | 204 | def detect_facescrub_landmarks(src_dir, templatelists_path, bbox, detector): 205 | # load json 206 | with open(templatelists_path, 'r') as f: 207 | data = json.load(f) 208 | rel_list = data['path'] 209 | 210 | landmarks = {} 211 | for rel_path in rel_list: 212 | # to fullpath 213 | path = os.path.join(src_dir, rel_path) 214 | img = cv2_imread(path) 215 | try: 216 | boxes, points = detector.detect_face(img) 217 | except: 218 | print('detect error:%s'%(path)) 219 | 220 | if points is None or len(points) == 0: 221 | continue 222 | 223 | # find the one largest IoU 224 | dir, fname = os.path.split(path) 225 | key, _ = os.path.splitext(fname) 226 | target_box = bbox[key] 227 | max_idx = 0 228 | max_iou = 0 229 | for i, box in enumerate(boxes): 230 | box = [box[0], box[1], box[2] - box[0], box[3] - box[1]] 231 | iou = IoU(box, target_box) 232 | if iou > max_iou: 233 | max_iou = iou 234 | max_idx = i 235 | landmarks[key] = points[max_idx].tolist() 236 | 237 | return landmarks 238 | 239 | 240 | def correct_facescrub_json(src_dir, dst_dir, dict, json_path): 241 | # load json 242 | with open(json_path, 'r') as f: 243 | data = json.load(f) 244 | print(data) 245 | for key, value in data.items(): 246 | name, image_id = key.split('_') 247 | path = os.path.join(src_dir,name+'/'+key+'.jpg') 248 | dst_path = translate_path(src_dir, dst_dir, path) 249 | target_box = dict[key] 250 | img = cv2_imread(path) 251 | point = data[key] 252 | xxyy = [] 253 | for i in range(5): 254 | xxyy.append(point[i*2]) 255 | for i in range(5): 256 | xxyy.append(point[i*2+1]) 257 | print(xxyy) 258 | print(key) 259 | max_chip = align_to_96x112(img, xxyy) 260 | makedirs(dst_path) 261 | #cv2_imwrite(dst_path, max_chip) 262 | draw_and_show(img, [target_box], [xxyy] ) 263 | cv2.imshow('chip', max_chip) 264 | ch = cv2.waitKey(0) 265 | 266 | def merge_landmarks(labeled_json, detect_json, dst_json): 267 | # load json 268 | with open(labeled_json, 'r') as f: 269 | data = json.load(f) 270 | # load detect 271 | with open(detect_json, 'r') as f: 272 | landmarks = json.load(f) 273 | # merge 274 | for key, value in data.items(): 275 | point = value 276 | xxyy = [] 277 | for i in range(5): 278 | xxyy.append(point[i*2]) 279 | for i in range(5): 280 | xxyy.append(point[i*2+1]) 281 | landmarks[key] = xxyy 282 | # output 283 | with open(dst_json, 'w') as f: 284 | f.write(json.dumps(landmarks)) 285 | print(len(landmarks)) 286 | 287 | def align_facescrub_by_landmark(src_dir, dst_dir, templatelists_path, landmarks_path): 288 | # path list 289 | with open(templatelists_path, 'r') as f: 290 | data = json.load(f) 291 | rel_list = data['path'] 292 | # landmarks 293 | with open(landmarks_path, 'r') as f: 294 | landmarks = json.load(f) 295 | 296 | for rel_path in rel_list: 297 | # to fullpath 298 | path = os.path.join(src_dir, rel_path) 299 | img = cv2_imread(path) 300 | dst_path = translate_path(src_dir, dst_dir, path) 301 | dir, fname = os.path.split(path) 302 | key, _ = os.path.splitext(fname) 303 | points = landmarks[key] 304 | max_chip = align_to_96x112(img, points) 305 | makedirs(dst_path) 306 | cv2_imwrite(dst_path, max_chip) 307 | #cv2.imshow('face', max_chip) 308 | #ch = cv2.waitKey(1) 309 | 310 | ''' 311 | wrong label:Richard Madden_48806 312 | ''' 313 | if __name__=='__main__': 314 | if len(sys.argv) < 3: 315 | print('facescrub_image_dir aligned_dir features_list_json_path') 316 | exit() 317 | # 318 | src_dir = sys.argv[1] 319 | dst_dir = sys.argv[2] 320 | templatelists_path = sys.argv[3] 321 | merged_json = './facescrub_80_landmark5.json' 322 | align_facescrub_by_landmark(src_dir, dst_dir, templatelists_path, merged_json) 323 | 324 | 325 | -------------------------------------------------------------------------------- /Megaface/align_megaface.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | import cv2 4 | import os 5 | import sys 6 | import time 7 | import os.path 8 | sys.path.insert(0, '../facealign') 9 | sys.path.insert(0, '../util') 10 | 11 | from fileutil import * 12 | from MtcnnPycaffe import MtcnnDetector, draw_and_show 13 | from alignment import FaceAlignVisitor, align_to_96x112 14 | from logfile import * 15 | 16 | import json 17 | import argparse 18 | 19 | def parse_Megaface_json(data): 20 | #print(data) 21 | count = 0 22 | # bound, points 23 | rect = [0,0,0,0] 24 | points = [None for i in range(10)] 25 | # bounding_box 26 | if 'bounding_box' in data: 27 | rect[0] = data['bounding_box']['x'] 28 | rect[1] = data['bounding_box']['y'] 29 | rect[2] = data['bounding_box']['width'] 30 | rect[3] = data['bounding_box']['height'] 31 | # to int 32 | rect = [int(i) for i in rect] 33 | # points 34 | landmarks = data['landmarks'] if 'landmarks' in data else None 35 | if landmarks is None: 36 | return rect, points, count 37 | 38 | for i in range(5): 39 | key = str(i) 40 | if key in landmarks: 41 | points[i] = landmarks[key]['x'] 42 | points[i+5] = landmarks[key]['y'] 43 | count += 1 44 | return rect, points, count 45 | 46 | 47 | def align_Megaface_fail_image(src_dir, dst_dir, path): 48 | # load image 49 | img = cv2.imread(path) 50 | dst_path = translate_path(src_dir, dst_dir, path) 51 | # has json 52 | json_path = path + ".json" 53 | if not os.path.exists(json_path): 54 | return False 55 | # load json 56 | with open(json_path, 'r') as f: 57 | data = json.load(f) 58 | # parse json 59 | rect, points, count = parse_Megaface_json(data) 60 | if count >= 2: # has key points 61 | aligned = align_to_96x112(img, points) 62 | #draw_and_show(img, [rect], [points]) 63 | cv2.waitKey(0) 64 | elif rect[2] > 0: # has bbox 65 | croped = img[rect[1]:(rect[1]+rect[3]),rect[0]:(rect[0]+rect[2])] 66 | aligned = cv2.resize(croped, dsize=(96,112)) 67 | else: # nothing, just crop 68 | aligned = cv2.resize(img, dsize=(96,112)) 69 | 70 | # save result 71 | makedirs(dst_path) 72 | cv2.imwrite(dst_path, aligned) 73 | return True 74 | 75 | 76 | class MegafaceFailVisitor(object): 77 | """ 78 | Megaface alignment 79 | """ 80 | def __init__(self, 81 | src_prefix, 82 | dst_prefix): 83 | 84 | self.src_prefix = src_prefix 85 | self.dst_prefix = dst_prefix 86 | 87 | def process(self, path): 88 | # JPG file 89 | title, ext = os.path.splitext(path) 90 | if ext.upper() != '.JPG': 91 | return True 92 | ret = align_Megaface_fail_image(self.src_prefix, self.dst_prefix, path) 93 | if not ret: 94 | print("Can't find json for :%s" % (path)) 95 | log_write(path) 96 | return ret 97 | 98 | 99 | def align_Megaface_fail(src_dir, dst_dir, todo_list, fail_list): 100 | visitor = MegafaceFailVisitor(src_dir,dst_dir) 101 | log_open(fail_list) 102 | list_walker(todo_list,visitor) 103 | log_close() 104 | 105 | 106 | def align_Megaface_detect(src_dir, dst_dir, fail_list, skip_exist=False, transform='similarity'): 107 | detector = MtcnnDetector( minsize=36 ) 108 | log_open(fail_list) 109 | visitor = FaceAlignVisitor(src_dir,dst_dir,detector, skip_exist=skip_exist, transform=transform) 110 | file_walker(src_dir,visitor) 111 | log_close() 112 | 113 | 114 | def load_Megaface_features_list(src_dir, json_path): 115 | # load json 116 | with open(json_path, 'r') as f: 117 | data = json.load(f) 118 | rel_list = data['path'] 119 | # to fullpath 120 | path_list = [ os.path.join(src_dir,p) for p in rel_list ] 121 | #print(path_list) 122 | return path_list 123 | 124 | def align_Megaface_features_list(src_dir, dst_dir, json_path): 125 | # load file list 126 | path_list = load_Megaface_features_list(src_dir,json_path) 127 | # init detector 128 | detector = MtcnnDetector( minsize=36 ) 129 | # align by detection 130 | visitor = FaceAlignVisitor(src_dir,dst_dir,detector) 131 | detect_fail_list = '~temp.txt' 132 | log_open(detect_fail_list) 133 | for i in range(len(path_list)): 134 | path = path_list[i] 135 | visitor.process(path) 136 | log_close() 137 | # align by meta 138 | align_Megaface_fail(src_dir, dst_dir, detect_fail_list, json_path+".fail.txt") 139 | 140 | 141 | def align_Megaface(src_dir, dst_dir, templatelists_dir): 142 | for i in range(1,7): 143 | set_size = 10**i 144 | json_path = 'megaface_features_list.json_%d_1' % (set_size) 145 | json_path = os.path.join(templatelists_dir,json_path) 146 | print(json_path) 147 | align_Megaface_features_list(src_dir, dst_dir, json_path) 148 | 149 | def main(): 150 | parser = argparse.ArgumentParser() 151 | parser.add_argument("-s", "--src_dir",help="Megaface image dir") 152 | parser.add_argument("-d", "--dst_dir",help="Aligned image dir") 153 | parser.add_argument("-l", "--fail_list", default='megafail.txt',help="Failed image list") 154 | parser.add_argument("-t", "--transform", default='similarity',help="similarity OR affine") 155 | parser.add_argument("-f", "--skip_exist", default=True,help="skip if aliged file exists") 156 | args = parser.parse_args() 157 | # get config 158 | src_dir = args.src_dir 159 | dst_dir = args.dst_dir 160 | fail_list = args.fail_list 161 | skip_exist = args.skip_exist 162 | transform = args.transform 163 | # detect 164 | detect_fail_list = '~detect-fail.txt' 165 | align_Megaface_detect(src_dir, dst_dir, detect_fail_list, skip_exist, transform) 166 | align_Megaface_fail(src_dir, dst_dir, detect_fail_list, fail_list) 167 | #os.remove(detect_fail_list) 168 | 169 | if __name__=='__main__': 170 | if len(sys.argv) < 3: 171 | print('megaface_image_dir aligned_dir distractor_templatelists_dir') 172 | exit() 173 | 174 | src_dir = sys.argv[1] 175 | dst_dir = sys.argv[2] 176 | templatelists_dir = sys.argv[3] 177 | align_Megaface(src_dir, dst_dir, templatelists_dir) 178 | 179 | 180 | -------------------------------------------------------------------------------- /Megaface/config.conf.example: -------------------------------------------------------------------------------- 1 | [facescrub] 2 | image_dir=YOUR_PATH/MegaFace/MegaFace 3 | aligned_dir=YOUR_PATH/MegaFace/MegaFace_aligned 4 | feature_dir=YOUR_PATH/MegaFace/MegaFace_features 5 | 6 | [megaface] 7 | image_dir=YOUR_PATH/MegaFace/facescrub 8 | aligned_dir=YOUR_PATH/MegaFace/facescrub_aligned 9 | feature_dir=YOUR_PATH/MegaFace/facescrub_features 10 | 11 | [devkit] 12 | templatelists_dir=YOUR_PATH/MegaFace/devkit/templatelists 13 | 14 | ; test models 15 | [model] 16 | name=model_1 17 | gpu_id=0 18 | feat_layer=fc5 19 | 20 | [model_1] 21 | model =model_1.prototxt 22 | weights=model_1.caffemodel 23 | suffix =_model_1.bin 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Megaface/extract_feature_list.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import cv2 3 | import os,sys 4 | import time 5 | import os.path 6 | 7 | sys.path.insert(0, '../facealign') 8 | sys.path.insert(0, '../util') 9 | 10 | from fileutil import * 11 | from caffe_extractor import CaffeExtractor 12 | from alignment import cv2_imread 13 | from matio import save_mat, load_mat 14 | from config import Config 15 | import json 16 | import argparse 17 | 18 | SKIP_EXIST = 0 19 | def extract_feature_list(rel_list, image_dir, feature_dir, suffix, extractor): 20 | total_size = len(rel_list) 21 | global SKIP_EXIST 22 | for i in range(total_size): 23 | if i % 100 == 0: 24 | print('%6d/%6d %s' % (i, total_size, rel_list[i])) 25 | # make fullpath 26 | path = os.path.join(image_dir, rel_list[i]) 27 | # feature path 28 | feat_path = translate_path(image_dir, feature_dir, path) 29 | feat_path = feat_path + suffix 30 | if SKIP_EXIST and os.path.exists(feat_path): 31 | continue 32 | img = cv2_imread(path) 33 | feat = extractor.extract_feature(img) 34 | makedirs(feat_path) 35 | save_mat(feat_path, feat) 36 | 37 | def load_feature_list(rel_list, image_dir, feature_dir, suffix): 38 | total_size = len(rel_list) 39 | featlist = [] 40 | for i in range(total_size): 41 | # make fullpath 42 | feat_path = os.path.join(feature_dir, rel_list[i]) 43 | feat_path = feat_path + suffix 44 | feat = load_mat(feat_path) 45 | featlist.append(feat) 46 | if i % 100 == 0: 47 | print('\t%d/%d\t%s' % (i, total_size, rel_list[i])) 48 | return featlist 49 | 50 | 51 | def extract_facescrub_uncropped(facescrub_dir, templatelists_dir, feature_dir, suffix, extractor): 52 | # load json 53 | json_path = os.path.join(templatelists_dir, 'facescrub_uncropped_features_list.json') 54 | with open(json_path, 'r') as f: 55 | data = json.load(f) 56 | rel_list = data['path'] 57 | 58 | extract_feature_list(rel_list, facescrub_dir, feature_dir, suffix, extractor) 59 | 60 | 61 | def extract_megaface_features_list(mega_dir, templatelist, feature_dir, suffix, extractor): 62 | # load json 63 | with open(templatelist, 'r') as f: 64 | data = json.load(f) 65 | rel_list = data['path'] 66 | 67 | extract_feature_list(rel_list, mega_dir, feature_dir, suffix, extractor) 68 | 69 | 70 | def extract_megaface_features(mega_dir, templatelists_dir, feature_dir, suffix, extractor): 71 | for i in range(1,7): 72 | set_size = 10**i 73 | json_path = 'megaface_features_list.json_%d_1' % (set_size) 74 | print('\n\nRun: '+json_path) 75 | json_path = os.path.join(templatelists_dir,json_path) 76 | extract_megaface_features_list(mega_dir, json_path, feature_dir, suffix, extractor) 77 | 78 | 79 | if __name__=='__main__': 80 | # config_file model_name 81 | if len(sys.argv) < 2: 82 | print('config_file [model_name]') 83 | exit(0) 84 | # read config 85 | config = Config(sys.argv[1]) 86 | # config 87 | model_name = config.get('model').name 88 | if len(sys.argv) >= 3: 89 | model_name = sys.argv[2] 90 | if config.get('model').skip_exist: 91 | SKIP_EXIST = config.get('model').skip_exist 92 | 93 | # load model 94 | feat_layer = 'fc5' 95 | if config.get('model').feat_layer: 96 | featLayer = config.get('model').feat_layer 97 | if config.get(model_name).feat_layer != None: 98 | feat_layer = config.get(model_name).feat_layer 99 | 100 | model = config.get(model_name).model 101 | weights = config.get(model_name).weights 102 | suffix = config.get(model_name).suffix 103 | 104 | print('Test model:%s feat:%s suffix:%s' % (model_name, feat_layer, suffix)) 105 | 106 | extractor = CaffeExtractor(model, weights, featLayer = feat_layer, 107 | gpu_id = config.get('model').gpu_id) 108 | 109 | # devkit/templatelists 110 | templatelists_dir = config.get('devkit').templatelists_dir 111 | 112 | # Extract facescrub features 113 | facescrub_dir = config.get('facescrub').aligned_dir 114 | facescrub_feature_dir = config.get('facescrub').feature_dir 115 | extract_facescrub_uncropped(facescrub_dir, templatelists_dir, facescrub_feature_dir, suffix, extractor) 116 | 117 | # Extract MegaFace features 118 | mega_dir = config.get('megaface').aligned_dir 119 | mega_feature_dir = config.get('megaface').feature_dir 120 | extract_megaface_features(mega_dir, templatelists_dir, mega_feature_dir, suffix, extractor) -------------------------------------------------------------------------------- /Megaface/facescrub_landmark.json: -------------------------------------------------------------------------------- 1 | {"Heath Ledger_23240":[1157,578,1397,578,1274,725,1172,863,1373,866], 2 | "Matthew Broderick_42082":[268,208,354,202,333,258,275,297,354,292], 3 | "Fran Drescher_22942":[394,166,428,177,412,180,387,200,416,209], 4 | "Bobbie Eakes_23541":[1037,321,1154,312,1088,382,1048,426,1157,415], 5 | "Chris Evans_10913":[492,316,589,311,586,401,499,459,566,457], 6 | "Chris Evans_11000":[338,209,410,195,399,239,366,289,421,277], 7 | "Daniel Day-Lewis_14388":[286,183,324,177,301,207,297,226,327,221], 8 | "Daniel Day-Lewis_14441":[233,137,280,138,252,167,238,183,271,184], 9 | "Emily Deschanel_20716":[908,358,1040,348,972,434,929,490,1034,479], 10 | "Emily Deschanel_20747":[1016,387,1114,378,1086,430,1034,491,1112,481], 11 | "Heath Ledger_23302":[312,280,390,271,365,327,333,375,397,363], 12 | "Hugh Jackman_23978":[533,125,572,120,568,143,542,167,572,164], 13 | "Ilene Kristen_40890":[292,120,327,117,312,140,295,155,327,153], 14 | "Ilene Kristen_40899":[211,140,254,131,244,158,218,182,257,176], 15 | "James Remar_27189":[224,109,271,111,245,143,226,161,267,161], 16 | "Joanna Kerns_40134":[399,263,465,272,424,313,398,334,460,339], 17 | "Justin Timberlake_36221":[445,111,490,109,467,139,451,158,480,158], 18 | "Kiefer Sutherland_38478":[335,177,394,183,381,219,330,248,376,251], 19 | "Kit Harington_38685":[205,94,242,94,220,119,210,136,236,135], 20 | "Pamela Anderson_2296":[194,232,241,235,213,258,194,277,230,281], 21 | "Patrick Warburton_46955":[589,291,720,298,704,339,628,446,716,449], 22 | "Rebecca Budig_10736":[257,504,305,504,287,525,262,544,298,544], 23 | "Richard Madden_48705":[2242,754,2614,750,2520,874,2240,1122,2624,1110], 24 | "Robert Duvall_49684":[935,445,973,446,958,472,929,486,969,487], 25 | "Ryan Phillippe_51711":[247,176,300,176,268,205,256,233,291,233], 26 | "Ryan Phillippe_51713":[564,225,664,221,590,271,581,338,652,331], 27 | "Sarah Hyland_36958":[213,166,270,166,232,194,222,221,263,221], 28 | "Stana Katic_39799":[428,466,619,460,470,573,451,641,636,631], 29 | "Terry Farrell_25098":[954,786,1144,766,1010,862,994,990,1134,982], 30 | "Victoria Justice_39077":[526,290,612,304,526,340,525,385,601,395], 31 | "Victoria Justice_39131":[554,233,678,231,586,304,562,346,682,343] 32 | } -------------------------------------------------------------------------------- /Megaface/matio.py: -------------------------------------------------------------------------------- 1 | import struct 2 | import numpy as np 3 | 4 | cv_type_to_dtype = { 5 | 5 : np.dtype('float32'), 6 | 6 : np.dtype('float64') 7 | } 8 | 9 | dtype_to_cv_type = {v : k for k,v in cv_type_to_dtype.items()} 10 | 11 | def write_mat(f, m): 12 | """Write mat m to file f""" 13 | if len(m.shape) == 1: 14 | rows = m.shape[0] 15 | cols = 1 16 | else: 17 | rows, cols = m.shape 18 | header = struct.pack('iiii', rows, cols, cols * 4, dtype_to_cv_type[m.dtype]) 19 | f.write(header) 20 | f.write(m.data) 21 | 22 | 23 | def read_mat(f): 24 | """ 25 | Reads an OpenCV mat from the given file opened in binary mode 26 | """ 27 | rows, cols, stride, type_ = struct.unpack('iiii', f.read(4*4)) 28 | mat = np.fromstring(f.read(rows*stride),dtype=cv_type_to_dtype[type_]) 29 | return mat.reshape(rows,cols) 30 | 31 | def read_mkl_vec(f): 32 | """ 33 | Reads an OpenCV mat from the given file opened in binary mode 34 | """ 35 | # Read past the header information 36 | f.read(4*4) 37 | 38 | length, stride, type_ = struct.unpack('iii', f.read(3*4)) 39 | mat = np.fromstring(f.read(length*4),dtype=np.float32) 40 | return mat 41 | 42 | def load_mkl_vec(filename): 43 | """ 44 | Reads a OpenCV Mat from the given filename 45 | """ 46 | return read_mkl_vec(open(filename,'rb')) 47 | 48 | def load_mat(filename): 49 | """ 50 | Reads a OpenCV Mat from the given filename 51 | """ 52 | return read_mat(open(filename,'rb')) 53 | 54 | def save_mat(filename, m): 55 | """Saves mat m to the given filename""" 56 | return write_mat(open(filename,'wb'), m) 57 | 58 | def main(): 59 | f = open('1_to_0.bin','rb') 60 | vx = read_mat(f) 61 | vy = read_mat(f) 62 | 63 | if __name__ == '__main__': 64 | main() 65 | -------------------------------------------------------------------------------- /Megaface/plot.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import random 3 | import itertools 4 | import json 5 | import sys 6 | 7 | def main(result_json, distractors): 8 | # load json 9 | with open(result_json, 'r') as f: 10 | data = json.load(f) 11 | cmc = data['cmc'] 12 | roc = data['roc'] 13 | 14 | train_color = [random.random(), random.random(), random.random()] # the color of line 15 | # cmc 16 | cmc_title = 'CMC Distractors-%d' % distractors 17 | figure_1 = plt.figure(1) 18 | plt.plot(cmc[0], cmc[1], color=train_color, linewidth=2) 19 | plt.title(cmc_title) 20 | plt.xlabel('Rank') 21 | plt.ylabel('Prob') 22 | plt.savefig(cmc_title+'.png') 23 | # roc 24 | roc_title = 'ROC Distractors-%d' % distractors 25 | figure_1 = plt.figure(2) 26 | plt.plot(roc[0], roc[1], color=train_color, linewidth=2) 27 | plt.title(roc_title) 28 | plt.xlabel('FAR') 29 | plt.ylabel('TAR') 30 | plt.savefig(roc_title+'.png') 31 | plt.show() 32 | 33 | if __name__ == '__main__': 34 | if len(sys.argv) < 2: 35 | print('result_json') 36 | exit() 37 | result_json = sys.argv[1] 38 | segs = result_json.split('_') 39 | distractors = int(segs[len(segs)-2]) 40 | main(result_json, distractors) 41 | -------------------------------------------------------------------------------- /Megaface/run_test.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import cv2 3 | import os,sys 4 | import time 5 | sys.path.insert(0, '../facealign') 6 | sys.path.insert(0, '../util') 7 | 8 | from fileutil import * 9 | from alignment import cv2_imread 10 | from matio import save_mat, load_mat 11 | import json 12 | import argparse 13 | import numpy as np 14 | 15 | def load_feature_list(rel_list, feature_dir, suffix): 16 | total_size = len(rel_list) 17 | featlist = [] 18 | for i in range(total_size): 19 | # make fullpath 20 | feat_path = os.path.join(feature_dir, rel_list[i]) 21 | feat_path = feat_path + suffix 22 | feat = load_mat(feat_path) 23 | featlist.append(feat) 24 | if i % 100 == 0: 25 | print('\t%d/%d\t%s' % (i, total_size, rel_list[i])) 26 | return featlist 27 | 28 | def load_probset(templatelist, feature_dir, suffix): 29 | # load json 30 | with open(templatelist, 'r') as f: 31 | data = json.load(f) 32 | probe_path = data['path'] 33 | prob_feat = load_feature_list(probe_path, feature_dir, suffix) 34 | data['feat'] = prob_feat 35 | return data 36 | 37 | def L2_distance(v1, v2): 38 | return np.sqrt(np.sum(np.square(v1 - v2))) 39 | 40 | def test_set(distractor_path, probe, feature_dir, suffix): 41 | # load distractor 42 | with open(distractor_path, 'r') as f: 43 | data = json.load(f) 44 | distractor_list = data['path'] 45 | # probe set 46 | T = len(probe['id']) 47 | probe_set = set() 48 | for id in probe['id']: 49 | probe_set.add(id) 50 | ids = list(probe_set) 51 | N = len(ids) 52 | pclass = {} 53 | for id in ids: 54 | pclass[id] = [] 55 | for i in range(len(probe['id'])): 56 | id = probe['id'][i] 57 | pclass[id].append(i) 58 | probe_id_list = probe['id'] 59 | probe_feat_list = probe['feat'] 60 | correct = 0 61 | wrong = 0 62 | # class 1,..., N 63 | for id in pclass: 64 | # i,...,M 65 | S = pclass[id] 66 | M = len(S) 67 | print('test id:%s' % id) 68 | for i in range(M): 69 | min_dist = 100000 70 | min_idx = 0 71 | probe_idx = S[i] 72 | probe_feat = probe_feat_list[probe_idx] 73 | probe_id = probe_id_list[probe_idx] 74 | # match distractors 75 | for j in range(len(distractor_list)): 76 | # make fullpath 77 | feat_path = os.path.join(feature_dir, distractor_list[j]) 78 | feat_path = feat_path + suffix 79 | feat = load_mat(feat_path) 80 | dist = L2_distance(feat,probe_feat) 81 | if dist < min_dist: 82 | min_dist = dist 83 | min_idx = j 84 | p2_dist = 100000 85 | p2_idx = 0 86 | # match probe 87 | ''' 88 | for j in range(T): 89 | if j == probe_idx: 90 | continue 91 | dist = L2_distance(probe_feat_list[j],probe_feat) 92 | if dist < p2_dist: 93 | p2_dist = dist 94 | p2_idx = j 95 | ''' 96 | for c in ids: 97 | if c != id: 98 | SS = pclass[c] 99 | MM = len(SS) 100 | II = np.random.randint(MM) 101 | j = SS[II] 102 | else: 103 | II = np.random.randint(M-1) 104 | II = II if II < i else (II+1) 105 | j = S[II] 106 | dist = L2_distance(probe_feat_list[j],probe_feat) 107 | if dist < p2_dist: 108 | p2_dist = dist 109 | p2_idx = j 110 | 111 | if p2_dist < min_dist: 112 | if probe['id'][p2_idx] == probe_id: 113 | print("TTT:%s\t %s %f" % (probe['path'][probe_idx], probe['path'][p2_idx], p2_dist)) 114 | else: 115 | print("FFF:%s\t %s %f" % (probe['path'][probe_idx], probe['path'][p2_idx], p2_dist)) 116 | else: 117 | print("FFF:%s\t %s %f" % (probe['path'][probe_idx], distractor_list[min_idx], min_dist)) 118 | 119 | # compare 120 | if p2_dist < min_dist and probe_id_list[p2_idx] == probe_id: 121 | correct += 1 122 | else: 123 | wrong += 1 124 | rank1_ratio = float(correct)/(correct+wrong) 125 | print('RandK-1:%f %d/%d' % (rank1_ratio, correct, (correct+wrong))) 126 | 127 | if __name__=='__main__': 128 | # config_file model_name 129 | if len(sys.argv) < 3: 130 | print('config_file distractors') 131 | exit(0) 132 | # read config 133 | config = Config(sys.argv[1]) 134 | distractors = sys.argv[2] 135 | # config 136 | model_name = config.get('model').name 137 | # load model 138 | model = config.get(model_name).model 139 | weights = config.get(model_name).weights 140 | suffix = config.get(model_name).suffix 141 | extractor = load_extractor(model, weights, config.get('model').gpu_id) 142 | 143 | # devkit/templatelists 144 | templatelists_dir = config.get('devkit').templatelists_dir 145 | 146 | facescrub_feature_dir = config.get('facescrub').feature_dir 147 | mega_feature_dir = config.get('megaface').feature_dir 148 | 149 | # devkit/templatelists 150 | probe = load_probset(templatelists_dir+'/facescrub_uncropped_features_list.json', 151 | facescrub_feature_dir, suffix) 152 | list_name = 'megaface_features_list.json_%s_1' % distractors 153 | test_set(templatelists_dir+'/' + list_name, probe, mega_feature_dir, suffix) 154 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Face dataset tools 2 | - Face detection & alignment with MTCNN-PyCaffe 3 | 4 | - Alignment script for Megaface and Facescrub(probe set, with precise landmarks) 5 | - LFW test scripts for PyCaffe -------------------------------------------------------------------------------- /facealign/MtcnnPycaffe.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | 3 | import os,sys 4 | os.environ['GLOG_minloglevel'] = '2' # Hide caffe debug info. 5 | 6 | import math 7 | import time 8 | 9 | import cv2 10 | import caffe 11 | 12 | import numpy as np 13 | import sys 14 | 15 | from alignment import alignface_96x112 16 | 17 | def draw_and_show(im, bboxes, points=None): 18 | '''Draw bboxes and points on image, and show. 19 | 20 | Args: 21 | im: image to draw on. 22 | bboxes: (tensor) bouding boxes sized [N,4]. 23 | points: (tensor) landmark points sized [N,10], 24 | coordinates arranged as [x,x,x,x,x,y,y,y,y,y]. 25 | ''' 26 | print('Drawing..') 27 | 28 | num_boxes = len(bboxes) 29 | for i in range(num_boxes): 30 | box = bboxes[i] 31 | if box[0] != None: 32 | x1 = int(box[0]) 33 | y1 = int(box[1]) 34 | x2 = int(box[2]) 35 | y2 = int(box[3]) 36 | print('Rect:', x1, y1, x2,y2) 37 | # As im is rotated, so need to swap x and y. 38 | cv2.rectangle(im, (x1,y1), (x2,y2), (0,255,255), 2) 39 | 40 | if len(points): 41 | p = points[i] 42 | for i in range(5): 43 | if p[i] != None: 44 | x = int(p[i]) 45 | y = int(p[i+5]) 46 | # Again, swap x and y. 47 | cv2.circle(im, (x,y), 1, (0,0,255), 2) 48 | 49 | cv2.imshow('result', im) 50 | #cv2.waitKey(0) 51 | 52 | def non_max_suppression(bboxes, threshold=0.5, mode='union'): 53 | '''Non max suppression. 54 | 55 | Args: 56 | bboxes: (tensor) bounding boxes and scores sized [N, 5]. 57 | threshold: (float) overlap threshold. 58 | mode: (str) 'union' or 'min'. 59 | 60 | Returns: 61 | Bboxes after nms. 62 | Picked indices. 63 | 64 | Ref: 65 | https://github.com/rbgirshick/py-faster-rcnn/blob/master/lib/nms/py_cpu_nms.py 66 | ''' 67 | x1 = bboxes[:,0] 68 | y1 = bboxes[:,1] 69 | x2 = bboxes[:,2] 70 | y2 = bboxes[:,3] 71 | scores = bboxes[:, 4] 72 | 73 | areas = (x2 - x1 + 1) * (y2 - y1 + 1) 74 | order = scores.argsort()[::-1] 75 | 76 | keep = [] 77 | while order.size > 0: 78 | i = order[0] 79 | keep.append(i) 80 | xx1 = np.maximum(x1[i], x1[order[1:]]) 81 | yy1 = np.maximum(y1[i], y1[order[1:]]) 82 | xx2 = np.minimum(x2[i], x2[order[1:]]) 83 | yy2 = np.minimum(y2[i], y2[order[1:]]) 84 | 85 | w = np.maximum(0.0, xx2 - xx1 + 1) 86 | h = np.maximum(0.0, yy2 - yy1 + 1) 87 | 88 | inter = w * h 89 | if mode == 'union': 90 | ovr = inter / (areas[i] + areas[order[1:]] - inter) 91 | elif mode == 'min': 92 | ovr = inter / np.minimum(areas[i], areas[order[1:]]) 93 | else: 94 | raise TypeError('Unknown nms mode: %s.' % mode ) 95 | 96 | inds = np.where(ovr <= threshold)[0] 97 | order = order[inds + 1] 98 | 99 | return bboxes[keep], keep 100 | 101 | def padding(bboxes, im_height, im_width): 102 | '''Padding bouding boxes the edge of image, if it's too large.''' 103 | bboxes[:,0] = np.maximum(0, bboxes[:,0]) 104 | bboxes[:,1] = np.maximum(0, bboxes[:,1]) 105 | bboxes[:,2] = np.minimum(im_width-1, bboxes[:,2]) 106 | bboxes[:,3] = np.minimum(im_height-1, bboxes[:,3]) 107 | return bboxes 108 | 109 | def bbox_to_square(bboxes): 110 | '''Make bounding boxes square.''' 111 | square_bbox = bboxes.copy() 112 | 113 | w = bboxes[:,2] - bboxes[:,0] + 1 114 | h = bboxes[:,3] - bboxes[:,1] + 1 115 | max_side = np.maximum(h,w) 116 | 117 | square_bbox[:,0] = bboxes[:,0] + (w - max_side) * 0.5 118 | square_bbox[:,1] = bboxes[:,1] + (h - max_side) * 0.5 119 | square_bbox[:,2] = square_bbox[:,0] + max_side - 1 120 | square_bbox[:,3] = square_bbox[:,1] + max_side - 1 121 | 122 | return square_bbox 123 | 124 | def bbox_regression(bboxes): 125 | '''Bounding box regression. 126 | 127 | Args: 128 | bboxes: (tensor) bounding boxes sized [N,9], containing: 129 | x1, y1, x2, y2, score, regy1, regx1, regy2, regx2. 130 | 131 | Return: 132 | Regressed bounding boxes sized [N,5]. 133 | ''' 134 | bbw = bboxes[:,2] - bboxes[:,0] + 1 135 | bbh = bboxes[:,3] - bboxes[:,1] + 1 136 | 137 | x1 = bboxes[:,0] 138 | y1 = bboxes[:,1] 139 | x2 = bboxes[:,2] 140 | y2 = bboxes[:,3] 141 | 142 | scores = bboxes[:,4] 143 | 144 | # Note the sequence. 145 | rgy1 = bboxes[:,5] 146 | rgx1 = bboxes[:,6] 147 | rgy2 = bboxes[:,7] 148 | rgx2 = bboxes[:,8] 149 | 150 | ret = np.vstack([x1 + rgx1 * bbw, 151 | y1 + rgy1 * bbh, 152 | x2 + rgx2 * bbw, 153 | y2 + rgy2 * bbh, 154 | scores]) 155 | return ret.T 156 | 157 | def get_pnet_boxes(outputs, scale, threshold): 158 | '''Generate bouding boxes from PNet outputs. 159 | 160 | Args: 161 | outputs: (dict) PNet outputs. 162 | scale: (float) image scale ration. 163 | threshold: (float) confidence threshold. 164 | 165 | Returns: 166 | A tensor representing generated bounding boxes sized [N,9]. 167 | ''' 168 | confidence = outputs['prob1'][0][1] # [H,W] 169 | regression = outputs['conv4-2'][0] # [4,H,W] 170 | 171 | # Filter out confidence > threshold. 172 | # Note: 173 | # y is the row-index. 174 | # x is the col-index. 175 | y, x = np.where(confidence > threshold) 176 | 177 | # Get regression outputs. 178 | reg_y1, reg_x1, reg_y2, reg_x2 = [regression[i,y,x] for i in range(4)] 179 | reg = np.array([reg_x1, reg_y1, reg_x2, reg_y2]) 180 | 181 | # Get scores. 182 | scores = confidence[y,x] # [N,] 183 | 184 | # Get face rects. 185 | stride = 2 186 | cell_size = 12 187 | 188 | x1 = np.round((stride*x+1) / scale) 189 | y1 = np.round((stride*y+1) / scale) 190 | x2 = np.round((stride*x+1 + cell_size-1) / scale) 191 | y2 = np.round((stride*y+1 + cell_size-1) / scale) 192 | rect = np.array([x1, y1, x2, y2]) 193 | 194 | bbox = np.vstack([rect, scores, reg]) # [9,N] 195 | return bbox.T # [N,9] 196 | 197 | def get_rnet_boxes(bboxes, outputs, threshold): 198 | '''Generate bounding boxes from RNet outputs. 199 | 200 | Args: 201 | bboxes: (tensor) PNet bouding boxes sized [N,5]. 202 | outputs: (dict) RNet outputs. 203 | threshold: (float) confidence threshold. 204 | 205 | Returns: 206 | A tensor representing generated bounding boxes sized [N,9]. 207 | ''' 208 | confidence = outputs['prob1'][:,1] 209 | regression = outputs['conv5-2'] 210 | 211 | indices = np.where(confidence > threshold) 212 | rects = bboxes[indices][:,0:4] # [N,4] 213 | scores = confidence[indices] # [N,] 214 | scores = scores.reshape(-1,1) # [N,1] 215 | regs = regression[indices] # [N,4] 216 | 217 | return np.hstack([rects, scores, regs]) # [N,9] 218 | 219 | def get_onet_boxes(bboxes, outputs, threshold): 220 | '''Generate bounding boxes and points from ONet outputs. 221 | 222 | Args: 223 | bboxes: (tensor) RNet bounding boxes sized [N,5]. 224 | outputs: (dict) ONet outputs. 225 | threshold: (float) confidence threshold. 226 | 227 | Returns: 228 | A tensor representing generated bounding boxes sized [N,9]. 229 | A tensor representing points sized [N,10]. 230 | ''' 231 | confidence = outputs['prob1'][:,1] 232 | regression = outputs['conv6-2'] 233 | points = outputs['conv6-3'] 234 | 235 | indices = np.where(confidence > threshold) 236 | 237 | rects = bboxes[indices][:,0:4] 238 | scores = confidence[indices] 239 | scores = scores.reshape(-1,1) 240 | regs = regression[indices] 241 | 242 | points = points[indices] # Note `y` is in the front. 243 | points_y = points[:,0:5] # [N,5] 244 | points_x = points[:,5:10] # [N,5] 245 | 246 | w = rects[:,2] - rects[:,0] + 1 247 | h = rects[:,3] - rects[:,1] + 1 248 | 249 | x1 = rects[:,0] 250 | y1 = rects[:,1] 251 | 252 | points_x = points_x * w.reshape(-1,1) + x1.reshape(-1,1) 253 | points_y = points_y * h.reshape(-1,1) + y1.reshape(-1,1) 254 | 255 | # We move `x` ahead, points=[x,x,x,x,x,y,y,y,y,y]. 256 | return np.hstack([rects, scores, regs]), np.hstack([points_x, points_y]) 257 | 258 | def get_inputs_from_bboxes(im, bboxes, size): 259 | '''Get network inputs based on generated bounding boxes. 260 | 261 | Args: 262 | im: (image) rotated original image. 263 | bboxes: (tensor) regressed bounding boxes sized [N,5]. 264 | size: (int) expected input size. 265 | 266 | Returns: 267 | A tensor sized [N, 3, size, size]. 268 | ''' 269 | num_boxes = bboxes.shape[0] 270 | inputs = np.zeros((num_boxes, size, size, 3), dtype=np.float32) 271 | for i in range(num_boxes): 272 | x1 = int(bboxes[i,0]) 273 | y1 = int(bboxes[i,1]) 274 | x2 = int(bboxes[i,2]) 275 | y2 = int(bboxes[i,3]) 276 | 277 | im_crop = im[y1:y2+1, x1:x2+1, :] 278 | inputs[i] = cv2.resize(im_crop, (size,size)) 279 | 280 | # [N,H,W,C] -> [N,C,H,W] to meet the Caffe needs. 281 | inputs = np.transpose(inputs, (0,3,1,2)) 282 | 283 | # Zero mean and normalization. 284 | inputs = (inputs - 127.5) * 0.0078125 285 | return inputs 286 | 287 | 288 | class MtcnnDetector(object): 289 | """ 290 | Joint Face Detection and Alignment using Multi-task Cascaded Convolutional Neural Networks 291 | see https://github.com/kpzhang93/MTCNN_face_detection_alignment 292 | this is a PyCaffe version 293 | """ 294 | def __init__(self, 295 | model_folder='./model/', 296 | minsize = 20, 297 | threshold = [0.6, 0.7, 0.7], 298 | factor = 0.709, 299 | gpu_id = 0): 300 | """ 301 | Initialize the detector 302 | 303 | Parameters: 304 | ---------- 305 | model_folder : string 306 | path for the models 307 | minsize : float number 308 | minimal face to detect 309 | threshold : float number 310 | detect threshold for 3 stages 311 | factor: float number 312 | scale factor for image pyramid 313 | num_worker: int number 314 | number of processes we use for first stage 315 | accurate_landmark: bool 316 | use accurate landmark localization or not 317 | 318 | """ 319 | caffe.set_mode_gpu() 320 | caffe.set_device(gpu_id) 321 | cwd = os.path.abspath(os.path.dirname(__file__)) 322 | model_folder = cwd + '/model/' 323 | # Load models. 324 | prototxt = [model_folder + x + '.prototxt' for x in ['det1', 'det2', 'det3']] 325 | binary = [model_folder + x + '.caffemodel' for x in ['det1', 'det2', 'det3']] 326 | self.PNet = caffe.Net(prototxt[0], binary[0], caffe.TEST) 327 | self.RNet = caffe.Net(prototxt[1], binary[1], caffe.TEST) 328 | self.ONet = caffe.Net(prototxt[2], binary[2], caffe.TEST) 329 | 330 | self.minsize = float(minsize) 331 | self.factor = float(factor) 332 | self.threshold = threshold 333 | 334 | 335 | def detect_face(self, im): 336 | """ 337 | detect face over img 338 | Parameters: 339 | ---------- 340 | img: numpy array, bgr order of shape (1, 3, n, m) 341 | input image 342 | Retures: 343 | ------- 344 | bboxes: numpy array, n x 5 (x1,y1,x2,y2,score) 345 | bboxes 346 | points: numpy array, n x 10 (x1, x2 ... x5, y1, y2 ..y5) 347 | landmarks 348 | """ 349 | im = im.astype(np.float32) 350 | im = cv2.cvtColor(im, cv2.COLOR_BGR2RGB) 351 | im = np.transpose(im, (1,0,2)) # Rotate image. 352 | 353 | image_height, image_width, num_channels = im.shape 354 | #print('Image shape:', im.shape) 355 | # convert gray to rgb 356 | if num_channels != 3: 357 | im = cv2.cvtColor(im, cv2.COLOR_GRAY2RGB) 358 | 359 | MIN_FACE_SIZE = self.minsize # Minimum face size. 360 | MIN_INPUT_SIZE = 12. # Minimum input size. 361 | MAX_INPUT_SIZE = 1024 362 | m = MIN_INPUT_SIZE / MIN_FACE_SIZE 363 | 364 | min_size = min(image_height, image_width) 365 | min_size = min_size * m 366 | 367 | scales = [] 368 | counter = 0 369 | FACTOR = self.factor 370 | while min_size >= MIN_INPUT_SIZE: 371 | if min_size <= MAX_INPUT_SIZE: 372 | scales.append(m * FACTOR**counter) 373 | min_size = min_size * FACTOR 374 | counter = counter + 1 375 | 376 | # Threshold for each stage. 377 | THRESHOLD = self.threshold 378 | PNet = self.PNet 379 | RNet = self.RNet 380 | ONet = self.ONet 381 | t1 = time.time() 382 | 383 | # -------------------------------------------------------------- 384 | # First stage. 385 | # 386 | total_boxes = [] # Bounding boxes of all scales. 387 | for scale in scales: 388 | hs = int(math.ceil(image_height*scale)) 389 | ws = int(math.ceil(image_width*scale)) 390 | 391 | im_resized = cv2.resize(im, (ws,hs), interpolation=cv2.INTER_AREA) 392 | #print('Resize to:', im_resized.shape) 393 | 394 | # H,W,C -> C,H,W 395 | im_resized = np.transpose(im_resized, (2,0,1)) 396 | 397 | # Zero mean and normalization. 398 | im_resized = (im_resized - 127.5) * 0.0078125 399 | 400 | # Reshape input layer. 401 | PNet.blobs['data'].reshape(1, 3, hs, ws) 402 | PNet.blobs['data'].data[...] = im_resized 403 | outputs = PNet.forward() 404 | 405 | bboxes = get_pnet_boxes(outputs, scale, THRESHOLD[0]) 406 | bboxes,_ = non_max_suppression(bboxes, 0.5) 407 | 408 | total_boxes.append(bboxes) 409 | 410 | total_boxes = np.vstack(total_boxes) 411 | 412 | bboxes,_ = non_max_suppression(total_boxes, 0.7) 413 | bboxes = bbox_regression(total_boxes) 414 | 415 | bboxes = bbox_to_square(bboxes) 416 | bboxes = padding(bboxes, image_height, image_width) 417 | 418 | #print('After PNet bboxes shape: ', bboxes.shape) 419 | if bboxes.shape[0] == 0: 420 | return [],[] 421 | 422 | # -------------------------------------------------------------- 423 | # Second stage. 424 | # 425 | inputs = get_inputs_from_bboxes(im, bboxes, 24) 426 | N,C,H,W = inputs.shape 427 | 428 | RNet.blobs['data'].reshape(N,3,H,W) 429 | RNet.blobs['data'].data[...] = inputs 430 | outputs = RNet.forward() 431 | 432 | bboxes = get_rnet_boxes(bboxes, outputs, THRESHOLD[1]) 433 | 434 | bboxes,_ = non_max_suppression(bboxes, 0.7) 435 | bboxes = bbox_regression(bboxes) 436 | bboxes = bbox_to_square(bboxes) 437 | bboxes = padding(bboxes, image_height, image_width) 438 | 439 | #print('After RNet bboxes shape: ', bboxes.shape) 440 | if bboxes.shape[0] == 0: 441 | return [],[] 442 | 443 | # -------------------------------------------------------------- 444 | # Third stage. 445 | # 446 | inputs = get_inputs_from_bboxes(im, bboxes, 48) 447 | N,C,H,W = inputs.shape 448 | 449 | ONet.blobs['data'].reshape(N,3,H,W) 450 | ONet.blobs['data'].data[...] = inputs 451 | outputs = ONet.forward() 452 | 453 | bboxes, points = get_onet_boxes(bboxes, outputs, THRESHOLD[2]) 454 | bboxes = bbox_regression(bboxes) 455 | 456 | bboxes, picked_indices = non_max_suppression(bboxes, 0.7, 'min') 457 | points = points[picked_indices] 458 | bboxes = padding(bboxes, image_height, image_width) 459 | 460 | #print('After ONet bboxes shape: ', bboxes.shape, '\n') 461 | if bboxes.shape[0] == 0: 462 | return [],[] 463 | 464 | t2 = time.time() 465 | #print('Total time: %.3fs\n' % (t2-t1)) 466 | # transpose points 467 | for i in range(len(points)): 468 | for j in range(5): 469 | t = points[i][j] 470 | points[i][j] = points[i][j+5] 471 | points[i][j+5] = t 472 | # tranpose bboxes 473 | for i in range(len(bboxes)): 474 | t = bboxes[i][0] 475 | bboxes[i][0] = bboxes[i][1] 476 | bboxes[i][1] = t 477 | t = bboxes[i][2] 478 | bboxes[i][2] = bboxes[i][3] 479 | bboxes[i][3] = t 480 | 481 | return bboxes, points 482 | 483 | 484 | if __name__ == '__main__': 485 | detector = MtcnnDetector() 486 | # Load image. 487 | im = cv2.imread(sys.argv[1]) 488 | bboxes,points = detector.detect_face(im) 489 | #draw_and_show(im, bboxes, points) 490 | aligned = alignface_96x112(im, points) 491 | cv2.imwrite('align.png', aligned[0]) 492 | -------------------------------------------------------------------------------- /facealign/README.md: -------------------------------------------------------------------------------- 1 | # Face detection & alignment with MTCNN-PyCaffe 2 | 3 | I wrapped the code of [pycaffe-mtcnn](https://github.com/kuangliu/pycaffe-mtcnn) to make it easier to use, and some tools for aligment is provided as well. 4 | 5 | ## Example code 6 | 7 | ``` 8 | if __name__ == '__main__': 9 | detector = MtcnnDetector() 10 | # Load image. 11 | im = cv2.imread(sys.argv[1]) 12 | bboxes,points = detector.detect_face(im) 13 | #draw_and_show(im, bboxes, points) 14 | aligned = alignface_96x112(im, points) 15 | cv2.imwrite('align.png', aligned[0]) 16 | ``` 17 | 18 | ## Alignment 19 | 20 | The `alignment` module provide functions to compute the `affine` and `similarity` transform matrix. 21 | 22 | compute_affine_transform 23 | compute_similarity_transform 24 | -------------------------------------------------------------------------------- /facealign/alignment.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | import os 3 | import numpy as np 4 | import math 5 | import cv2 6 | from fileutil import * 7 | from logfile import * 8 | 9 | def compute_affine_transform(points, refpoints, w = None): 10 | ''' 11 | compute the affine tranform matrix 12 | ''' 13 | if w == None: 14 | w = [1] * (len(points) * 2) 15 | assert(len(w) == 2*len(points)) 16 | y = [] 17 | for n, p in enumerate(refpoints): 18 | y += [p[0]/w[n*2], p[1]/w[n*2+1]] 19 | A = [] 20 | for n, p in enumerate(points): 21 | A.extend([ [p[0]/w[n*2], p[1]/w[n*2], 0, 0, 1/w[n*2], 0], [0, 0, p[0]/w[n*2+1], p[1]/w[n*2+1], 0, 1/w[n*2+1]] ]) 22 | 23 | lstsq = cv2.solve(np.array(A), np.array(y), flags=cv2.DECOMP_SVD) 24 | h11, h12, h21, h22, dx, dy = lstsq[1] 25 | 26 | #R = np.array([[h11, h12, dx], [h21, h22, dy]]) 27 | # The row above works too - but creates a redundant dimension 28 | R = np.array([[h11[0], h12[0], dx[0]], [h21[0], h22[0], dy[0]]]) 29 | return R 30 | 31 | 32 | def compute_similarity_transform(src, dst): 33 | ''' 34 | compute the similarity tranform matrix 35 | ''' 36 | assert len(src) == len(dst) 37 | N = len(src) 38 | A = np.zeros((N*2, 4), dtype=np.float) 39 | B = np.zeros((N*2, 1), dtype=np.float) 40 | for i in range(N): 41 | # x' 42 | row = i * 2 43 | A[row][0] = src[i][0] 44 | A[row][1] = -src[i][1] 45 | A[row][2] = 1 46 | A[row][3] = 0 47 | B[row][0] = dst[i][0] 48 | # y' 49 | row += 1 50 | A[row][0] = src[i][1] 51 | A[row][1] = src[i][0] 52 | A[row][2] = 0 53 | A[row][3] = 1 54 | B[row][0] = dst[i][1] 55 | AT = np.transpose(A) 56 | invAA = np.linalg.inv(np.dot(AT,A)) 57 | AAT = np.dot(invAA,AT) 58 | X = np.dot(AAT,B) 59 | 60 | R = np.array([[X[0], -X[1], X[2]], [X[1], X[0], X[3]]]) 61 | return R 62 | 63 | def cv2_imread(path): 64 | img = cv2.imread(path) 65 | if img is not None: 66 | return img 67 | # try .png 68 | print('Not find:%s try:%s' % (path, path+'.png')) 69 | img = cv2.imread(path+'.png') 70 | return img 71 | 72 | 73 | def cv2_imwrite(path,img): 74 | ret = True 75 | title, ext = os.path.splitext(path) 76 | ext = ext.lower() 77 | makedirs(path) 78 | # append gif with .png 79 | if ext == '.gif': 80 | ext = '.png' 81 | path = path+'.png' 82 | elif ext == '': 83 | path = path+'.png' 84 | 85 | try: 86 | cv2.imwrite(path, img) 87 | except: 88 | ret = False 89 | 90 | return ret 91 | 92 | 93 | def alignface_96x112(img, points, pading=0, trans_type = 'similarity'): 94 | """ 95 | crop and align face 96 | Parameters: 97 | ---------- 98 | img: numpy array, bgr order of shape (1, 3, n, m) 99 | input image 100 | points: numpy array, n x 10 (x1, x2 ... x5, y1, y2 ..y5) 101 | padding: default 0 102 | trans_type: similarity OR affine, default similarity 103 | Return: 104 | ------- 105 | crop_imgs: list, n 106 | cropped and aligned faces 107 | """ 108 | # average positions of face points 109 | mean_face_shape_x = [30.2946, 65.5318, 48.0252, 33.5493, 62.7299] 110 | mean_face_shape_y = [51.6963, 51.5014, 71.7366, 92.3655, 92.2041] 111 | # tranform 112 | tranform = compute_similarity_transform 113 | if trans_type == 'affine' : 114 | tranform = compute_affine_transform 115 | # do the job 116 | crop_imgs = [] 117 | for p in points: 118 | shape =[] 119 | for k in range(int(len(p)/2)): 120 | shape.append(p[k]) 121 | shape.append(p[k+5]) 122 | 123 | from_points = [] 124 | to_points = [] 125 | 126 | for i in range(int(len(shape)/2)): 127 | x = mean_face_shape_x[i] + pading 128 | y = mean_face_shape_y[i] + pading 129 | to_points.append([x, y]) 130 | from_points.append([shape[2*i], shape[2*i+1]]) 131 | 132 | N = tranform(from_points,to_points) 133 | chips = cv2.warpAffine(img, N, (96+2*pading, 112+2*pading) ) 134 | crop_imgs.append(chips) 135 | 136 | return crop_imgs 137 | 138 | 139 | def align_to_96x112(img, points, pading=0, trans_type = 'similarity'): 140 | """ 141 | crop and align face 142 | Parameters: 143 | ---------- 144 | img: numpy array, bgr order of shape (1, 3, n, m) 145 | input image 146 | points: list, 1 x 10 (x1, x2 ... x5, y1, y2 ..y5) 147 | padding: default 0 148 | trans_type: similarity OR affine, default similarity 149 | Return: 150 | ------- 151 | cropped and aligned face 152 | """ 153 | # average positions of face points 154 | mean_face_shape_x = [30.2946, 65.5318, 48.0252, 33.5493, 62.7299] 155 | mean_face_shape_y = [51.6963, 51.5014, 71.7366, 92.3655, 92.2041] 156 | # tranform 157 | tranform = compute_similarity_transform 158 | if trans_type == 'affine' : 159 | tranform = compute_affine_transform 160 | # do the job 161 | from_points = [] 162 | to_points = [] 163 | 164 | for i in range(int(len(points)/2)): 165 | if points[i] == None: 166 | continue 167 | x = mean_face_shape_x[i] + pading 168 | y = mean_face_shape_y[i] + pading 169 | to_points.append([x, y]) 170 | from_points.append([points[i], points[i + 5]]) 171 | 172 | N = tranform(from_points,to_points) 173 | chip = cv2.warpAffine(img, N, (96+2*pading, 112+2*pading) ) 174 | return chip 175 | 176 | 177 | def align_to_112x112(img, points, pading=0, trans_type = 'similarity'): 178 | """ 179 | crop and align face 180 | Parameters: 181 | ---------- 182 | img: numpy array, bgr order of shape (1, 3, n, m) 183 | input image 184 | points: list, 1 x 10 (x1, x2 ... x5, y1, y2 ..y5) 185 | padding: default 0 186 | trans_type: similarity OR affine, default similarity 187 | Return: 188 | ------- 189 | cropped and aligned face 190 | """ 191 | # average positions of face points 192 | mean_face_shape_x = [30.2946, 65.5318, 48.0252, 33.5493, 62.7299] 193 | mean_face_shape_y = [51.6963, 51.5014, 71.7366, 92.3655, 92.2041] 194 | # tranform 195 | tranform = compute_similarity_transform 196 | if trans_type == 'affine' : 197 | tranform = compute_affine_transform 198 | # do the job 199 | from_points = [] 200 | to_points = [] 201 | 202 | for i in range(int(len(points)/2)): 203 | if points[i] == None: 204 | continue 205 | x = mean_face_shape_x[i] + pading + 8.0 206 | y = mean_face_shape_y[i] + pading 207 | to_points.append([x, y]) 208 | from_points.append([points[i], points[i + 5]]) 209 | 210 | N = tranform(from_points,to_points) 211 | chip = cv2.warpAffine(img, N, (112+2*pading, 112+2*pading) ) 212 | return chip 213 | 214 | 215 | class FaceAlignVisitor(object): 216 | """ 217 | Megaface alignment 218 | """ 219 | def __init__(self, 220 | src_prefix, 221 | dst_prefix, 222 | detector, 223 | skip_exist = True, 224 | transform = 'similarity', 225 | pading = 0): 226 | 227 | self.src_prefix = src_prefix 228 | self.dst_prefix = dst_prefix 229 | self.skip_exist = skip_exist 230 | self.detector = detector 231 | self.transform = transform 232 | self.pading = pading 233 | # statistic 234 | self.done_count = 0 235 | self.fail_count = 0 236 | 237 | 238 | def process(self, path): 239 | if not is_image_file(path): 240 | return True 241 | 242 | dst_path = translate_path(self.src_prefix, self.dst_prefix, path) 243 | 244 | if self.skip_exist and os.path.exists(dst_path): 245 | # print('skip:%s' % path) 246 | return True 247 | #print('%s -> %s' % (path, dst_path)) 248 | img = cv2_imread(path) 249 | if img is None: 250 | print('load error:%s'%(path)) 251 | log_write(path) 252 | self.fail_count += 1 253 | return False 254 | 255 | #print('run:%s/%s'%(subdir,filename)) 256 | try: 257 | boxes, points = self.detector.detect_face(img) 258 | except: 259 | print('detect error:%s'%(path)) 260 | log_write(path) 261 | self.fail_count += 1 262 | return False 263 | if points is None or len(points) == 0: 264 | log_write(path) 265 | self.fail_count += 1 266 | return False 267 | 268 | # find biggest face 269 | max_idx = 0 270 | max_width = 0 271 | for i, box in enumerate(boxes): 272 | if box[2] > max_width: 273 | max_width = box[2] 274 | max_idx = i 275 | max_chip = align_to_96x112(img, points[max_idx], self.pading, trans_type = self.transform) 276 | #draw_and_show(img,boxes, points ) 277 | #cv2.imshow('chip', max_chip) 278 | #cv2.waitKey(0) 279 | makedirs(dst_path) 280 | ret = cv2_imwrite(dst_path, max_chip) 281 | if ret == False: 282 | print('imwrite error:%s'%(path)) 283 | log_write(path) 284 | self.fail_count += 1 285 | return False 286 | 287 | # report 288 | if self.done_count % 100 == 0: 289 | print('done:%05d, fail:%05d img:%s'%(self.done_count, self.fail_count, path)) 290 | 291 | self.done_count += 1 292 | return True -------------------------------------------------------------------------------- /facealign/model/det1.caffemodel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cnzeki/face-datasets/0c1d14961ead8c087dd9d9361b78dc55ffb42aa3/facealign/model/det1.caffemodel -------------------------------------------------------------------------------- /facealign/model/det1.prototxt: -------------------------------------------------------------------------------- 1 | name: "PNet" 2 | input: "data" 3 | input_dim: 1 4 | input_dim: 3 5 | input_dim: 12 6 | input_dim: 12 7 | 8 | layer { 9 | name: "conv1" 10 | type: "Convolution" 11 | bottom: "data" 12 | top: "conv1" 13 | param { 14 | lr_mult: 1 15 | decay_mult: 1 16 | } 17 | param { 18 | lr_mult: 2 19 | decay_mult: 0 20 | } 21 | convolution_param { 22 | num_output: 10 23 | kernel_size: 3 24 | stride: 1 25 | weight_filler { 26 | type: "xavier" 27 | } 28 | bias_filler { 29 | type: "constant" 30 | value: 0 31 | } 32 | } 33 | } 34 | layer { 35 | name: "PReLU1" 36 | type: "PReLU" 37 | bottom: "conv1" 38 | top: "conv1" 39 | } 40 | layer { 41 | name: "pool1" 42 | type: "Pooling" 43 | bottom: "conv1" 44 | top: "pool1" 45 | pooling_param { 46 | pool: MAX 47 | kernel_size: 2 48 | stride: 2 49 | } 50 | } 51 | 52 | layer { 53 | name: "conv2" 54 | type: "Convolution" 55 | bottom: "pool1" 56 | top: "conv2" 57 | param { 58 | lr_mult: 1 59 | decay_mult: 1 60 | } 61 | param { 62 | lr_mult: 2 63 | decay_mult: 0 64 | } 65 | convolution_param { 66 | num_output: 16 67 | kernel_size: 3 68 | stride: 1 69 | weight_filler { 70 | type: "xavier" 71 | } 72 | bias_filler { 73 | type: "constant" 74 | value: 0 75 | } 76 | } 77 | } 78 | layer { 79 | name: "PReLU2" 80 | type: "PReLU" 81 | bottom: "conv2" 82 | top: "conv2" 83 | } 84 | 85 | layer { 86 | name: "conv3" 87 | type: "Convolution" 88 | bottom: "conv2" 89 | top: "conv3" 90 | param { 91 | lr_mult: 1 92 | decay_mult: 1 93 | } 94 | param { 95 | lr_mult: 2 96 | decay_mult: 0 97 | } 98 | convolution_param { 99 | num_output: 32 100 | kernel_size: 3 101 | stride: 1 102 | weight_filler { 103 | type: "xavier" 104 | } 105 | bias_filler { 106 | type: "constant" 107 | value: 0 108 | } 109 | } 110 | } 111 | layer { 112 | name: "PReLU3" 113 | type: "PReLU" 114 | bottom: "conv3" 115 | top: "conv3" 116 | } 117 | 118 | 119 | layer { 120 | name: "conv4-1" 121 | type: "Convolution" 122 | bottom: "conv3" 123 | top: "conv4-1" 124 | param { 125 | lr_mult: 1 126 | decay_mult: 1 127 | } 128 | param { 129 | lr_mult: 2 130 | decay_mult: 0 131 | } 132 | convolution_param { 133 | num_output: 2 134 | kernel_size: 1 135 | stride: 1 136 | weight_filler { 137 | type: "xavier" 138 | } 139 | bias_filler { 140 | type: "constant" 141 | value: 0 142 | } 143 | } 144 | } 145 | 146 | layer { 147 | name: "conv4-2" 148 | type: "Convolution" 149 | bottom: "conv3" 150 | top: "conv4-2" 151 | param { 152 | lr_mult: 1 153 | decay_mult: 1 154 | } 155 | param { 156 | lr_mult: 2 157 | decay_mult: 0 158 | } 159 | convolution_param { 160 | num_output: 4 161 | kernel_size: 1 162 | stride: 1 163 | weight_filler { 164 | type: "xavier" 165 | } 166 | bias_filler { 167 | type: "constant" 168 | value: 0 169 | } 170 | } 171 | } 172 | layer { 173 | name: "prob1" 174 | type: "Softmax" 175 | bottom: "conv4-1" 176 | top: "prob1" 177 | } 178 | -------------------------------------------------------------------------------- /facealign/model/det2.caffemodel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cnzeki/face-datasets/0c1d14961ead8c087dd9d9361b78dc55ffb42aa3/facealign/model/det2.caffemodel -------------------------------------------------------------------------------- /facealign/model/det2.prototxt: -------------------------------------------------------------------------------- 1 | name: "RNet" 2 | input: "data" 3 | input_dim: 1 4 | input_dim: 3 5 | input_dim: 24 6 | input_dim: 24 7 | 8 | 9 | ########################## 10 | ###################### 11 | layer { 12 | name: "conv1" 13 | type: "Convolution" 14 | bottom: "data" 15 | top: "conv1" 16 | param { 17 | lr_mult: 0 18 | decay_mult: 0 19 | } 20 | param { 21 | lr_mult: 0 22 | decay_mult: 0 23 | } 24 | convolution_param { 25 | num_output: 28 26 | kernel_size: 3 27 | stride: 1 28 | weight_filler { 29 | type: "xavier" 30 | } 31 | bias_filler { 32 | type: "constant" 33 | value: 0 34 | } 35 | } 36 | } 37 | layer { 38 | name: "prelu1" 39 | type: "PReLU" 40 | bottom: "conv1" 41 | top: "conv1" 42 | propagate_down: true 43 | } 44 | layer { 45 | name: "pool1" 46 | type: "Pooling" 47 | bottom: "conv1" 48 | top: "pool1" 49 | pooling_param { 50 | pool: MAX 51 | kernel_size: 3 52 | stride: 2 53 | } 54 | } 55 | 56 | layer { 57 | name: "conv2" 58 | type: "Convolution" 59 | bottom: "pool1" 60 | top: "conv2" 61 | param { 62 | lr_mult: 0 63 | decay_mult: 0 64 | } 65 | param { 66 | lr_mult: 0 67 | decay_mult: 0 68 | } 69 | convolution_param { 70 | num_output: 48 71 | kernel_size: 3 72 | stride: 1 73 | weight_filler { 74 | type: "xavier" 75 | } 76 | bias_filler { 77 | type: "constant" 78 | value: 0 79 | } 80 | } 81 | } 82 | layer { 83 | name: "prelu2" 84 | type: "PReLU" 85 | bottom: "conv2" 86 | top: "conv2" 87 | propagate_down: true 88 | } 89 | layer { 90 | name: "pool2" 91 | type: "Pooling" 92 | bottom: "conv2" 93 | top: "pool2" 94 | pooling_param { 95 | pool: MAX 96 | kernel_size: 3 97 | stride: 2 98 | } 99 | } 100 | #################################### 101 | 102 | ################################## 103 | layer { 104 | name: "conv3" 105 | type: "Convolution" 106 | bottom: "pool2" 107 | top: "conv3" 108 | param { 109 | lr_mult: 0 110 | decay_mult: 0 111 | } 112 | param { 113 | lr_mult: 0 114 | decay_mult: 0 115 | } 116 | convolution_param { 117 | num_output: 64 118 | kernel_size: 2 119 | stride: 1 120 | weight_filler { 121 | type: "xavier" 122 | } 123 | bias_filler { 124 | type: "constant" 125 | value: 0 126 | } 127 | } 128 | } 129 | layer { 130 | name: "prelu3" 131 | type: "PReLU" 132 | bottom: "conv3" 133 | top: "conv3" 134 | propagate_down: true 135 | } 136 | ############################### 137 | 138 | ############################### 139 | 140 | layer { 141 | name: "conv4" 142 | type: "InnerProduct" 143 | bottom: "conv3" 144 | top: "conv4" 145 | param { 146 | lr_mult: 0 147 | decay_mult: 0 148 | } 149 | param { 150 | lr_mult: 0 151 | decay_mult: 0 152 | } 153 | inner_product_param { 154 | num_output: 128 155 | weight_filler { 156 | type: "xavier" 157 | } 158 | bias_filler { 159 | type: "constant" 160 | value: 0 161 | } 162 | } 163 | } 164 | layer { 165 | name: "prelu4" 166 | type: "PReLU" 167 | bottom: "conv4" 168 | top: "conv4" 169 | } 170 | 171 | layer { 172 | name: "conv5-1" 173 | type: "InnerProduct" 174 | bottom: "conv4" 175 | top: "conv5-1" 176 | param { 177 | lr_mult: 0 178 | decay_mult: 0 179 | } 180 | param { 181 | lr_mult: 0 182 | decay_mult: 0 183 | } 184 | inner_product_param { 185 | num_output: 2 186 | #kernel_size: 1 187 | #stride: 1 188 | weight_filler { 189 | type: "xavier" 190 | } 191 | bias_filler { 192 | type: "constant" 193 | value: 0 194 | } 195 | } 196 | } 197 | layer { 198 | name: "conv5-2" 199 | type: "InnerProduct" 200 | bottom: "conv4" 201 | top: "conv5-2" 202 | param { 203 | lr_mult: 1 204 | decay_mult: 1 205 | } 206 | param { 207 | lr_mult: 2 208 | decay_mult: 1 209 | } 210 | inner_product_param { 211 | num_output: 4 212 | #kernel_size: 1 213 | #stride: 1 214 | weight_filler { 215 | type: "xavier" 216 | } 217 | bias_filler { 218 | type: "constant" 219 | value: 0 220 | } 221 | } 222 | } 223 | layer { 224 | name: "prob1" 225 | type: "Softmax" 226 | bottom: "conv5-1" 227 | top: "prob1" 228 | } -------------------------------------------------------------------------------- /facealign/model/det3.caffemodel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cnzeki/face-datasets/0c1d14961ead8c087dd9d9361b78dc55ffb42aa3/facealign/model/det3.caffemodel -------------------------------------------------------------------------------- /facealign/model/det3.prototxt: -------------------------------------------------------------------------------- 1 | name: "ONet" 2 | input: "data" 3 | input_dim: 1 4 | input_dim: 3 5 | input_dim: 48 6 | input_dim: 48 7 | ################################## 8 | layer { 9 | name: "conv1" 10 | type: "Convolution" 11 | bottom: "data" 12 | top: "conv1" 13 | param { 14 | lr_mult: 1 15 | decay_mult: 1 16 | } 17 | param { 18 | lr_mult: 2 19 | decay_mult: 1 20 | } 21 | convolution_param { 22 | num_output: 32 23 | kernel_size: 3 24 | stride: 1 25 | weight_filler { 26 | type: "xavier" 27 | } 28 | bias_filler { 29 | type: "constant" 30 | value: 0 31 | } 32 | } 33 | } 34 | layer { 35 | name: "prelu1" 36 | type: "PReLU" 37 | bottom: "conv1" 38 | top: "conv1" 39 | } 40 | layer { 41 | name: "pool1" 42 | type: "Pooling" 43 | bottom: "conv1" 44 | top: "pool1" 45 | pooling_param { 46 | pool: MAX 47 | kernel_size: 3 48 | stride: 2 49 | } 50 | } 51 | layer { 52 | name: "conv2" 53 | type: "Convolution" 54 | bottom: "pool1" 55 | top: "conv2" 56 | param { 57 | lr_mult: 1 58 | decay_mult: 1 59 | } 60 | param { 61 | lr_mult: 2 62 | decay_mult: 1 63 | } 64 | convolution_param { 65 | num_output: 64 66 | kernel_size: 3 67 | stride: 1 68 | weight_filler { 69 | type: "xavier" 70 | } 71 | bias_filler { 72 | type: "constant" 73 | value: 0 74 | } 75 | } 76 | } 77 | 78 | layer { 79 | name: "prelu2" 80 | type: "PReLU" 81 | bottom: "conv2" 82 | top: "conv2" 83 | } 84 | layer { 85 | name: "pool2" 86 | type: "Pooling" 87 | bottom: "conv2" 88 | top: "pool2" 89 | pooling_param { 90 | pool: MAX 91 | kernel_size: 3 92 | stride: 2 93 | } 94 | } 95 | 96 | layer { 97 | name: "conv3" 98 | type: "Convolution" 99 | bottom: "pool2" 100 | top: "conv3" 101 | param { 102 | lr_mult: 1 103 | decay_mult: 1 104 | } 105 | param { 106 | lr_mult: 2 107 | decay_mult: 1 108 | } 109 | convolution_param { 110 | num_output: 64 111 | kernel_size: 3 112 | weight_filler { 113 | type: "xavier" 114 | } 115 | bias_filler { 116 | type: "constant" 117 | value: 0 118 | } 119 | } 120 | } 121 | layer { 122 | name: "prelu3" 123 | type: "PReLU" 124 | bottom: "conv3" 125 | top: "conv3" 126 | } 127 | layer { 128 | name: "pool3" 129 | type: "Pooling" 130 | bottom: "conv3" 131 | top: "pool3" 132 | pooling_param { 133 | pool: MAX 134 | kernel_size: 2 135 | stride: 2 136 | } 137 | } 138 | layer { 139 | name: "conv4" 140 | type: "Convolution" 141 | bottom: "pool3" 142 | top: "conv4" 143 | param { 144 | lr_mult: 1 145 | decay_mult: 1 146 | } 147 | param { 148 | lr_mult: 2 149 | decay_mult: 1 150 | } 151 | convolution_param { 152 | num_output: 128 153 | kernel_size: 2 154 | weight_filler { 155 | type: "xavier" 156 | } 157 | bias_filler { 158 | type: "constant" 159 | value: 0 160 | } 161 | } 162 | } 163 | layer { 164 | name: "prelu4" 165 | type: "PReLU" 166 | bottom: "conv4" 167 | top: "conv4" 168 | } 169 | 170 | 171 | layer { 172 | name: "conv5" 173 | type: "InnerProduct" 174 | bottom: "conv4" 175 | top: "conv5" 176 | param { 177 | lr_mult: 1 178 | decay_mult: 1 179 | } 180 | param { 181 | lr_mult: 2 182 | decay_mult: 1 183 | } 184 | inner_product_param { 185 | #kernel_size: 3 186 | num_output: 256 187 | weight_filler { 188 | type: "xavier" 189 | } 190 | bias_filler { 191 | type: "constant" 192 | value: 0 193 | } 194 | } 195 | } 196 | 197 | layer { 198 | name: "drop5" 199 | type: "Dropout" 200 | bottom: "conv5" 201 | top: "conv5" 202 | dropout_param { 203 | dropout_ratio: 0.25 204 | } 205 | } 206 | layer { 207 | name: "prelu5" 208 | type: "PReLU" 209 | bottom: "conv5" 210 | top: "conv5" 211 | } 212 | 213 | 214 | layer { 215 | name: "conv6-1" 216 | type: "InnerProduct" 217 | bottom: "conv5" 218 | top: "conv6-1" 219 | param { 220 | lr_mult: 1 221 | decay_mult: 1 222 | } 223 | param { 224 | lr_mult: 2 225 | decay_mult: 1 226 | } 227 | inner_product_param { 228 | #kernel_size: 1 229 | num_output: 2 230 | weight_filler { 231 | type: "xavier" 232 | } 233 | bias_filler { 234 | type: "constant" 235 | value: 0 236 | } 237 | } 238 | } 239 | layer { 240 | name: "conv6-2" 241 | type: "InnerProduct" 242 | bottom: "conv5" 243 | top: "conv6-2" 244 | param { 245 | lr_mult: 1 246 | decay_mult: 1 247 | } 248 | param { 249 | lr_mult: 2 250 | decay_mult: 1 251 | } 252 | inner_product_param { 253 | #kernel_size: 1 254 | num_output: 4 255 | weight_filler { 256 | type: "xavier" 257 | } 258 | bias_filler { 259 | type: "constant" 260 | value: 0 261 | } 262 | } 263 | } 264 | layer { 265 | name: "conv6-3" 266 | type: "InnerProduct" 267 | bottom: "conv5" 268 | top: "conv6-3" 269 | param { 270 | lr_mult: 1 271 | decay_mult: 1 272 | } 273 | param { 274 | lr_mult: 2 275 | decay_mult: 1 276 | } 277 | inner_product_param { 278 | #kernel_size: 1 279 | num_output: 10 280 | weight_filler { 281 | type: "xavier" 282 | } 283 | bias_filler { 284 | type: "constant" 285 | value: 0 286 | } 287 | } 288 | } 289 | layer { 290 | name: "prob1" 291 | type: "Softmax" 292 | bottom: "conv6-1" 293 | top: "prob1" 294 | } 295 | -------------------------------------------------------------------------------- /facealign/model/det4.caffemodel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cnzeki/face-datasets/0c1d14961ead8c087dd9d9361b78dc55ffb42aa3/facealign/model/det4.caffemodel -------------------------------------------------------------------------------- /facealign/model/det4.prototxt: -------------------------------------------------------------------------------- 1 | name: "LNet" 2 | input: "data" 3 | input_dim: 1 4 | input_dim: 15 5 | input_dim: 24 6 | input_dim: 24 7 | 8 | layer { 9 | name: "slicer_data" 10 | type: "Slice" 11 | bottom: "data" 12 | top: "data241" 13 | top: "data242" 14 | top: "data243" 15 | top: "data244" 16 | top: "data245" 17 | slice_param { 18 | axis: 1 19 | slice_point: 3 20 | slice_point: 6 21 | slice_point: 9 22 | slice_point: 12 23 | } 24 | } 25 | layer { 26 | name: "conv1_1" 27 | type: "Convolution" 28 | bottom: "data241" 29 | top: "conv1_1" 30 | param { 31 | lr_mult: 1 32 | decay_mult: 1 33 | } 34 | param { 35 | lr_mult: 2 36 | decay_mult: 1 37 | } 38 | convolution_param { 39 | num_output: 28 40 | kernel_size: 3 41 | stride: 1 42 | weight_filler { 43 | type: "xavier" 44 | } 45 | bias_filler { 46 | type: "constant" 47 | value: 0 48 | } 49 | } 50 | 51 | } 52 | layer { 53 | name: "prelu1_1" 54 | type: "PReLU" 55 | bottom: "conv1_1" 56 | top: "conv1_1" 57 | 58 | } 59 | layer { 60 | name: "pool1_1" 61 | type: "Pooling" 62 | bottom: "conv1_1" 63 | top: "pool1_1" 64 | pooling_param { 65 | pool: MAX 66 | kernel_size: 3 67 | stride: 2 68 | } 69 | } 70 | 71 | layer { 72 | name: "conv2_1" 73 | type: "Convolution" 74 | bottom: "pool1_1" 75 | top: "conv2_1" 76 | param { 77 | lr_mult: 1 78 | decay_mult: 1 79 | } 80 | param { 81 | lr_mult: 2 82 | decay_mult: 1 83 | } 84 | convolution_param { 85 | num_output: 48 86 | kernel_size: 3 87 | stride: 1 88 | weight_filler { 89 | type: "xavier" 90 | } 91 | bias_filler { 92 | type: "constant" 93 | value: 0 94 | } 95 | } 96 | 97 | } 98 | layer { 99 | name: "prelu2_1" 100 | type: "PReLU" 101 | bottom: "conv2_1" 102 | top: "conv2_1" 103 | } 104 | layer { 105 | name: "pool2_1" 106 | type: "Pooling" 107 | bottom: "conv2_1" 108 | top: "pool2_1" 109 | pooling_param { 110 | pool: MAX 111 | kernel_size: 3 112 | stride: 2 113 | } 114 | 115 | } 116 | layer { 117 | name: "conv3_1" 118 | type: "Convolution" 119 | bottom: "pool2_1" 120 | top: "conv3_1" 121 | param { 122 | lr_mult: 1 123 | decay_mult: 1 124 | } 125 | param { 126 | lr_mult: 2 127 | decay_mult: 1 128 | } 129 | convolution_param { 130 | num_output: 64 131 | kernel_size: 2 132 | stride: 1 133 | weight_filler { 134 | type: "xavier" 135 | } 136 | bias_filler { 137 | type: "constant" 138 | value: 0 139 | } 140 | } 141 | 142 | } 143 | layer { 144 | name: "prelu3_1" 145 | type: "PReLU" 146 | bottom: "conv3_1" 147 | top: "conv3_1" 148 | } 149 | ########################## 150 | layer { 151 | name: "conv1_2" 152 | type: "Convolution" 153 | bottom: "data242" 154 | top: "conv1_2" 155 | param { 156 | lr_mult: 1 157 | decay_mult: 1 158 | } 159 | param { 160 | lr_mult: 2 161 | decay_mult: 1 162 | } 163 | convolution_param { 164 | num_output: 28 165 | kernel_size: 3 166 | stride: 1 167 | weight_filler { 168 | type: "xavier" 169 | } 170 | bias_filler { 171 | type: "constant" 172 | value: 0 173 | } 174 | } 175 | 176 | } 177 | layer { 178 | name: "prelu1_2" 179 | type: "PReLU" 180 | bottom: "conv1_2" 181 | top: "conv1_2" 182 | 183 | } 184 | layer { 185 | name: "pool1_2" 186 | type: "Pooling" 187 | bottom: "conv1_2" 188 | top: "pool1_2" 189 | pooling_param { 190 | pool: MAX 191 | kernel_size: 3 192 | stride: 2 193 | } 194 | } 195 | 196 | layer { 197 | name: "conv2_2" 198 | type: "Convolution" 199 | bottom: "pool1_2" 200 | top: "conv2_2" 201 | param { 202 | lr_mult: 1 203 | decay_mult: 1 204 | } 205 | param { 206 | lr_mult: 2 207 | decay_mult: 1 208 | } 209 | convolution_param { 210 | num_output: 48 211 | kernel_size: 3 212 | stride: 1 213 | weight_filler { 214 | type: "xavier" 215 | } 216 | bias_filler { 217 | type: "constant" 218 | value: 0 219 | } 220 | } 221 | 222 | } 223 | layer { 224 | name: "prelu2_2" 225 | type: "PReLU" 226 | bottom: "conv2_2" 227 | top: "conv2_2" 228 | } 229 | layer { 230 | name: "pool2_2" 231 | type: "Pooling" 232 | bottom: "conv2_2" 233 | top: "pool2_2" 234 | pooling_param { 235 | pool: MAX 236 | kernel_size: 3 237 | stride: 2 238 | } 239 | 240 | } 241 | layer { 242 | name: "conv3_2" 243 | type: "Convolution" 244 | bottom: "pool2_2" 245 | top: "conv3_2" 246 | param { 247 | lr_mult: 1 248 | decay_mult: 1 249 | } 250 | param { 251 | lr_mult: 2 252 | decay_mult: 1 253 | } 254 | convolution_param { 255 | num_output: 64 256 | kernel_size: 2 257 | stride: 1 258 | weight_filler { 259 | type: "xavier" 260 | } 261 | bias_filler { 262 | type: "constant" 263 | value: 0 264 | } 265 | } 266 | 267 | } 268 | layer { 269 | name: "prelu3_2" 270 | type: "PReLU" 271 | bottom: "conv3_2" 272 | top: "conv3_2" 273 | } 274 | ########################## 275 | ########################## 276 | layer { 277 | name: "conv1_3" 278 | type: "Convolution" 279 | bottom: "data243" 280 | top: "conv1_3" 281 | param { 282 | lr_mult: 1 283 | decay_mult: 1 284 | } 285 | param { 286 | lr_mult: 2 287 | decay_mult: 1 288 | } 289 | convolution_param { 290 | num_output: 28 291 | kernel_size: 3 292 | stride: 1 293 | weight_filler { 294 | type: "xavier" 295 | } 296 | bias_filler { 297 | type: "constant" 298 | value: 0 299 | } 300 | } 301 | 302 | } 303 | layer { 304 | name: "prelu1_3" 305 | type: "PReLU" 306 | bottom: "conv1_3" 307 | top: "conv1_3" 308 | 309 | } 310 | layer { 311 | name: "pool1_3" 312 | type: "Pooling" 313 | bottom: "conv1_3" 314 | top: "pool1_3" 315 | pooling_param { 316 | pool: MAX 317 | kernel_size: 3 318 | stride: 2 319 | } 320 | } 321 | 322 | layer { 323 | name: "conv2_3" 324 | type: "Convolution" 325 | bottom: "pool1_3" 326 | top: "conv2_3" 327 | param { 328 | lr_mult: 1 329 | decay_mult: 1 330 | } 331 | param { 332 | lr_mult: 2 333 | decay_mult: 1 334 | } 335 | convolution_param { 336 | num_output: 48 337 | kernel_size: 3 338 | stride: 1 339 | weight_filler { 340 | type: "xavier" 341 | } 342 | bias_filler { 343 | type: "constant" 344 | value: 0 345 | } 346 | } 347 | 348 | } 349 | layer { 350 | name: "prelu2_3" 351 | type: "PReLU" 352 | bottom: "conv2_3" 353 | top: "conv2_3" 354 | } 355 | layer { 356 | name: "pool2_3" 357 | type: "Pooling" 358 | bottom: "conv2_3" 359 | top: "pool2_3" 360 | pooling_param { 361 | pool: MAX 362 | kernel_size: 3 363 | stride: 2 364 | } 365 | 366 | } 367 | layer { 368 | name: "conv3_3" 369 | type: "Convolution" 370 | bottom: "pool2_3" 371 | top: "conv3_3" 372 | param { 373 | lr_mult: 1 374 | decay_mult: 1 375 | } 376 | param { 377 | lr_mult: 2 378 | decay_mult: 1 379 | } 380 | convolution_param { 381 | num_output: 64 382 | kernel_size: 2 383 | stride: 1 384 | weight_filler { 385 | type: "xavier" 386 | } 387 | bias_filler { 388 | type: "constant" 389 | value: 0 390 | } 391 | } 392 | 393 | } 394 | layer { 395 | name: "prelu3_3" 396 | type: "PReLU" 397 | bottom: "conv3_3" 398 | top: "conv3_3" 399 | } 400 | ########################## 401 | ########################## 402 | layer { 403 | name: "conv1_4" 404 | type: "Convolution" 405 | bottom: "data244" 406 | top: "conv1_4" 407 | param { 408 | lr_mult: 1 409 | decay_mult: 1 410 | } 411 | param { 412 | lr_mult: 2 413 | decay_mult: 1 414 | } 415 | convolution_param { 416 | num_output: 28 417 | kernel_size: 3 418 | stride: 1 419 | weight_filler { 420 | type: "xavier" 421 | } 422 | bias_filler { 423 | type: "constant" 424 | value: 0 425 | } 426 | } 427 | 428 | } 429 | layer { 430 | name: "prelu1_4" 431 | type: "PReLU" 432 | bottom: "conv1_4" 433 | top: "conv1_4" 434 | 435 | } 436 | layer { 437 | name: "pool1_4" 438 | type: "Pooling" 439 | bottom: "conv1_4" 440 | top: "pool1_4" 441 | pooling_param { 442 | pool: MAX 443 | kernel_size: 3 444 | stride: 2 445 | } 446 | } 447 | 448 | layer { 449 | name: "conv2_4" 450 | type: "Convolution" 451 | bottom: "pool1_4" 452 | top: "conv2_4" 453 | param { 454 | lr_mult: 1 455 | decay_mult: 1 456 | } 457 | param { 458 | lr_mult: 2 459 | decay_mult: 1 460 | } 461 | convolution_param { 462 | num_output: 48 463 | kernel_size: 3 464 | stride: 1 465 | weight_filler { 466 | type: "xavier" 467 | } 468 | bias_filler { 469 | type: "constant" 470 | value: 0 471 | } 472 | } 473 | 474 | } 475 | layer { 476 | name: "prelu2_4" 477 | type: "PReLU" 478 | bottom: "conv2_4" 479 | top: "conv2_4" 480 | } 481 | layer { 482 | name: "pool2_4" 483 | type: "Pooling" 484 | bottom: "conv2_4" 485 | top: "pool2_4" 486 | pooling_param { 487 | pool: MAX 488 | kernel_size: 3 489 | stride: 2 490 | } 491 | 492 | } 493 | layer { 494 | name: "conv3_4" 495 | type: "Convolution" 496 | bottom: "pool2_4" 497 | top: "conv3_4" 498 | param { 499 | lr_mult: 1 500 | decay_mult: 1 501 | } 502 | param { 503 | lr_mult: 2 504 | decay_mult: 1 505 | } 506 | convolution_param { 507 | num_output: 64 508 | kernel_size: 2 509 | stride: 1 510 | weight_filler { 511 | type: "xavier" 512 | } 513 | bias_filler { 514 | type: "constant" 515 | value: 0 516 | } 517 | } 518 | 519 | } 520 | layer { 521 | name: "prelu3_4" 522 | type: "PReLU" 523 | bottom: "conv3_4" 524 | top: "conv3_4" 525 | } 526 | ########################## 527 | ########################## 528 | layer { 529 | name: "conv1_5" 530 | type: "Convolution" 531 | bottom: "data245" 532 | top: "conv1_5" 533 | param { 534 | lr_mult: 1 535 | decay_mult: 1 536 | } 537 | param { 538 | lr_mult: 2 539 | decay_mult: 1 540 | } 541 | convolution_param { 542 | num_output: 28 543 | kernel_size: 3 544 | stride: 1 545 | weight_filler { 546 | type: "xavier" 547 | } 548 | bias_filler { 549 | type: "constant" 550 | value: 0 551 | } 552 | } 553 | 554 | } 555 | layer { 556 | name: "prelu1_5" 557 | type: "PReLU" 558 | bottom: "conv1_5" 559 | top: "conv1_5" 560 | 561 | } 562 | layer { 563 | name: "pool1_5" 564 | type: "Pooling" 565 | bottom: "conv1_5" 566 | top: "pool1_5" 567 | pooling_param { 568 | pool: MAX 569 | kernel_size: 3 570 | stride: 2 571 | } 572 | } 573 | 574 | layer { 575 | name: "conv2_5" 576 | type: "Convolution" 577 | bottom: "pool1_5" 578 | top: "conv2_5" 579 | param { 580 | lr_mult: 1 581 | decay_mult: 1 582 | } 583 | param { 584 | lr_mult: 2 585 | decay_mult: 1 586 | } 587 | convolution_param { 588 | num_output: 48 589 | kernel_size: 3 590 | stride: 1 591 | weight_filler { 592 | type: "xavier" 593 | } 594 | bias_filler { 595 | type: "constant" 596 | value: 0 597 | } 598 | } 599 | 600 | } 601 | layer { 602 | name: "prelu2_5" 603 | type: "PReLU" 604 | bottom: "conv2_5" 605 | top: "conv2_5" 606 | } 607 | layer { 608 | name: "pool2_5" 609 | type: "Pooling" 610 | bottom: "conv2_5" 611 | top: "pool2_5" 612 | pooling_param { 613 | pool: MAX 614 | kernel_size: 3 615 | stride: 2 616 | } 617 | 618 | } 619 | layer { 620 | name: "conv3_5" 621 | type: "Convolution" 622 | bottom: "pool2_5" 623 | top: "conv3_5" 624 | param { 625 | lr_mult: 1 626 | decay_mult: 1 627 | } 628 | param { 629 | lr_mult: 2 630 | decay_mult: 1 631 | } 632 | convolution_param { 633 | num_output: 64 634 | kernel_size: 2 635 | stride: 1 636 | weight_filler { 637 | type: "xavier" 638 | } 639 | bias_filler { 640 | type: "constant" 641 | value: 0 642 | } 643 | } 644 | 645 | } 646 | layer { 647 | name: "prelu3_5" 648 | type: "PReLU" 649 | bottom: "conv3_5" 650 | top: "conv3_5" 651 | } 652 | ########################## 653 | layer { 654 | name: "concat" 655 | bottom: "conv3_1" 656 | bottom: "conv3_2" 657 | bottom: "conv3_3" 658 | bottom: "conv3_4" 659 | bottom: "conv3_5" 660 | top: "conv3" 661 | type: "Concat" 662 | concat_param { 663 | axis: 1 664 | } 665 | } 666 | ########################## 667 | layer { 668 | name: "fc4" 669 | type: "InnerProduct" 670 | bottom: "conv3" 671 | top: "fc4" 672 | param { 673 | lr_mult: 1 674 | decay_mult: 1 675 | } 676 | param { 677 | lr_mult: 2 678 | decay_mult: 1 679 | } 680 | inner_product_param { 681 | num_output: 256 682 | weight_filler { 683 | type: "xavier" 684 | } 685 | bias_filler { 686 | type: "constant" 687 | value: 0 688 | } 689 | } 690 | 691 | } 692 | layer { 693 | name: "prelu4" 694 | type: "PReLU" 695 | bottom: "fc4" 696 | top: "fc4" 697 | } 698 | ############################ 699 | layer { 700 | name: "fc4_1" 701 | type: "InnerProduct" 702 | bottom: "fc4" 703 | top: "fc4_1" 704 | param { 705 | lr_mult: 1 706 | decay_mult: 1 707 | } 708 | param { 709 | lr_mult: 2 710 | decay_mult: 1 711 | } 712 | inner_product_param { 713 | num_output: 64 714 | weight_filler { 715 | type: "xavier" 716 | } 717 | bias_filler { 718 | type: "constant" 719 | value: 0 720 | } 721 | } 722 | 723 | } 724 | layer { 725 | name: "prelu4_1" 726 | type: "PReLU" 727 | bottom: "fc4_1" 728 | top: "fc4_1" 729 | } 730 | layer { 731 | name: "fc5_1" 732 | type: "InnerProduct" 733 | bottom: "fc4_1" 734 | top: "fc5_1" 735 | param { 736 | lr_mult: 1 737 | decay_mult: 1 738 | } 739 | param { 740 | lr_mult: 2 741 | decay_mult: 1 742 | } 743 | inner_product_param { 744 | num_output: 2 745 | weight_filler { 746 | type: "xavier" 747 | #type: "constant" 748 | #value: 0 749 | } 750 | bias_filler { 751 | type: "constant" 752 | value: 0 753 | } 754 | } 755 | } 756 | 757 | 758 | ######################### 759 | layer { 760 | name: "fc4_2" 761 | type: "InnerProduct" 762 | bottom: "fc4" 763 | top: "fc4_2" 764 | param { 765 | lr_mult: 1 766 | decay_mult: 1 767 | } 768 | param { 769 | lr_mult: 2 770 | decay_mult: 1 771 | } 772 | inner_product_param { 773 | num_output: 64 774 | weight_filler { 775 | type: "xavier" 776 | } 777 | bias_filler { 778 | type: "constant" 779 | value: 0 780 | } 781 | } 782 | 783 | } 784 | layer { 785 | name: "prelu4_2" 786 | type: "PReLU" 787 | bottom: "fc4_2" 788 | top: "fc4_2" 789 | } 790 | layer { 791 | name: "fc5_2" 792 | type: "InnerProduct" 793 | bottom: "fc4_2" 794 | top: "fc5_2" 795 | param { 796 | lr_mult: 1 797 | decay_mult: 1 798 | } 799 | param { 800 | lr_mult: 2 801 | decay_mult: 1 802 | } 803 | inner_product_param { 804 | num_output: 2 805 | weight_filler { 806 | type: "xavier" 807 | #type: "constant" 808 | #value: 0 809 | } 810 | bias_filler { 811 | type: "constant" 812 | value: 0 813 | } 814 | } 815 | } 816 | 817 | ######################### 818 | layer { 819 | name: "fc4_3" 820 | type: "InnerProduct" 821 | bottom: "fc4" 822 | top: "fc4_3" 823 | param { 824 | lr_mult: 1 825 | decay_mult: 1 826 | } 827 | param { 828 | lr_mult: 2 829 | decay_mult: 1 830 | } 831 | inner_product_param { 832 | num_output: 64 833 | weight_filler { 834 | type: "xavier" 835 | } 836 | bias_filler { 837 | type: "constant" 838 | value: 0 839 | } 840 | } 841 | 842 | } 843 | layer { 844 | name: "prelu4_3" 845 | type: "PReLU" 846 | bottom: "fc4_3" 847 | top: "fc4_3" 848 | } 849 | layer { 850 | name: "fc5_3" 851 | type: "InnerProduct" 852 | bottom: "fc4_3" 853 | top: "fc5_3" 854 | param { 855 | lr_mult: 1 856 | decay_mult: 1 857 | } 858 | param { 859 | lr_mult: 2 860 | decay_mult: 1 861 | } 862 | inner_product_param { 863 | num_output: 2 864 | weight_filler { 865 | type: "xavier" 866 | #type: "constant" 867 | #value: 0 868 | } 869 | bias_filler { 870 | type: "constant" 871 | value: 0 872 | } 873 | } 874 | } 875 | 876 | ######################### 877 | layer { 878 | name: "fc4_4" 879 | type: "InnerProduct" 880 | bottom: "fc4" 881 | top: "fc4_4" 882 | param { 883 | lr_mult: 1 884 | decay_mult: 1 885 | } 886 | param { 887 | lr_mult: 2 888 | decay_mult: 1 889 | } 890 | inner_product_param { 891 | num_output: 64 892 | weight_filler { 893 | type: "xavier" 894 | } 895 | bias_filler { 896 | type: "constant" 897 | value: 0 898 | } 899 | } 900 | 901 | } 902 | layer { 903 | name: "prelu4_4" 904 | type: "PReLU" 905 | bottom: "fc4_4" 906 | top: "fc4_4" 907 | } 908 | layer { 909 | name: "fc5_4" 910 | type: "InnerProduct" 911 | bottom: "fc4_4" 912 | top: "fc5_4" 913 | param { 914 | lr_mult: 1 915 | decay_mult: 1 916 | } 917 | param { 918 | lr_mult: 2 919 | decay_mult: 1 920 | } 921 | inner_product_param { 922 | num_output: 2 923 | weight_filler { 924 | type: "xavier" 925 | #type: "constant" 926 | #value: 0 927 | } 928 | bias_filler { 929 | type: "constant" 930 | value: 0 931 | } 932 | } 933 | } 934 | 935 | ######################### 936 | layer { 937 | name: "fc4_5" 938 | type: "InnerProduct" 939 | bottom: "fc4" 940 | top: "fc4_5" 941 | param { 942 | lr_mult: 1 943 | decay_mult: 1 944 | } 945 | param { 946 | lr_mult: 2 947 | decay_mult: 1 948 | } 949 | inner_product_param { 950 | num_output: 64 951 | weight_filler { 952 | type: "xavier" 953 | } 954 | bias_filler { 955 | type: "constant" 956 | value: 0 957 | } 958 | } 959 | 960 | } 961 | layer { 962 | name: "prelu4_5" 963 | type: "PReLU" 964 | bottom: "fc4_5" 965 | top: "fc4_5" 966 | } 967 | layer { 968 | name: "fc5_5" 969 | type: "InnerProduct" 970 | bottom: "fc4_5" 971 | top: "fc5_5" 972 | param { 973 | lr_mult: 1 974 | decay_mult: 1 975 | } 976 | param { 977 | lr_mult: 2 978 | decay_mult: 1 979 | } 980 | inner_product_param { 981 | num_output: 2 982 | weight_filler { 983 | type: "xavier" 984 | #type: "constant" 985 | #value: 0 986 | } 987 | bias_filler { 988 | type: "constant" 989 | value: 0 990 | } 991 | } 992 | } 993 | 994 | ######################### 995 | 996 | -------------------------------------------------------------------------------- /util/caffe_extractor.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | import os,sys 3 | os.environ['GLOG_minloglevel'] = '2' # Hide caffe debug info. 4 | 5 | import caffe 6 | import cv2 as cv 7 | import numpy as np 8 | 9 | 10 | class CaffeExtractor: 11 | def __init__(self,model,weight,do_mirror=False,featLayer='fc5', gpu_id = 0): 12 | caffe.set_mode_gpu() 13 | caffe.set_device(gpu_id) 14 | 15 | self.featLayer = featLayer 16 | self.model = model 17 | self.weight = weight 18 | self.do_mirror = do_mirror 19 | self.net = caffe.Net(model, weight, caffe.TEST) 20 | 21 | @staticmethod 22 | def norm_image(_im): 23 | #im = cv.cvtColor(im, cv.COLOR_RGB2BGR) 24 | img32 = np.float32(_im) 25 | #img = _im.astype(np.float32) 26 | img = (img32 - 127.5) / 128 27 | img = np.transpose(img, [2, 0, 1]) 28 | return img 29 | 30 | def extract_image(self, im): 31 | # im = caffe.io.load_image(img_path) 32 | # self.net.blobs['data'].data[...] = self.transformer.preprocess('data', im) 33 | img = self.norm_image(im) 34 | #print(img) 35 | self.net.blobs['data'].data[...] = img 36 | self.net.forward() 37 | feat1 = self.net.blobs[self.featLayer].data[0].flatten() 38 | return feat1 39 | 40 | def extract_feature(self, im): 41 | feat1 = self.extract_image(im) 42 | if self.do_mirror == False: 43 | return feat1 44 | 45 | flip = cv.flip(im, 1) 46 | feat2 = self.extract_image(flip) 47 | 48 | return np.concatenate([feat1, feat2]) 49 | 50 | 51 | def extract(self, img_path): 52 | im = cv.imread(img_path) 53 | return self.extract_feature(im) 54 | 55 | 56 | -------------------------------------------------------------------------------- /util/config.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | import os 3 | import ConfigParser 4 | 5 | class OperationalError(Exception): 6 | """operation error.""" 7 | 8 | 9 | class Dictionary(dict): 10 | """ custom dict.""" 11 | 12 | def __getattr__(self, key): 13 | return self.get(key, None) 14 | 15 | __setattr__ = dict.__setitem__ 16 | __delattr__ = dict.__delitem__ 17 | 18 | 19 | class Config: 20 | def __init__(self, cfg="config.conf"): 21 | """ 22 | @param file_name: file name without extension. 23 | @param cfg: configuration file path. 24 | """ 25 | config = ConfigParser.ConfigParser() 26 | config.read(cfg) 27 | 28 | for section in config.sections(): 29 | setattr(self, section, Dictionary()) 30 | for name, raw_value in config.items(section): 31 | try: 32 | # Ugly fix to avoid '0' and '1' to be parsed as a 33 | # boolean value. 34 | # We raise an exception to goto fail^w parse it 35 | # as integer. 36 | if config.get(section, name) in ["0", "1"]: 37 | raise ValueError 38 | 39 | value = config.getboolean(section, name) 40 | except ValueError: 41 | try: 42 | value = config.getint(section, name) 43 | except ValueError: 44 | value = config.get(section, name) 45 | 46 | setattr(getattr(self, section), name, value) 47 | 48 | def get(self, section): 49 | """Get option. 50 | @param section: section to fetch. 51 | @return: option value. 52 | """ 53 | try: 54 | return getattr(self, section) 55 | except AttributeError as e: 56 | raise OperationalError("Option %s is not found in " 57 | "configuration, error: %s" % 58 | (section, e)) 59 | 60 | -------------------------------------------------------------------------------- /util/distance.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | import math 4 | import numpy as np 5 | 6 | def cosine_similarity(v1, v2): 7 | # compute cosine similarity of v1 to v2: (v1 dot v2)/{||v1||*||v2||) 8 | sumxx, sumxy, sumyy = 0, 0, 0 9 | for i in range(len(v1)): 10 | x = v1[i] 11 | y = v2[i] 12 | sumxx += x * x 13 | sumyy += y * y 14 | sumxy += x * y 15 | return sumxy / math.sqrt(sumxx * sumyy) 16 | 17 | 18 | def cosine_distance(v1, v2): 19 | return 1 - cosine_similarity(v1, v2) 20 | 21 | 22 | def L2_distance(v1, v2): 23 | return np.sqrt(np.sum(np.square(v1 - v2))) 24 | 25 | 26 | def SSD_distance(v1, v2): 27 | return np.sum(np.square(v1 - v2)) 28 | 29 | 30 | def get_distance(dist_type): 31 | loss_map = {'cosine':cosine_distance, 'L2':L2_distance, 'SSD':SSD_distance} 32 | return loss_map[dist_type] 33 | 34 | 35 | -------------------------------------------------------------------------------- /util/fileutil.py: -------------------------------------------------------------------------------- 1 | import os 2 | import time 3 | import os.path 4 | 5 | def translate_path(src_prefix, dst_prefix, path): 6 | sp = src_prefix.replace('\\','/') 7 | dp = dst_prefix.replace('\\','/') 8 | p = path.replace('\\','/') 9 | # src -> dst 10 | if path.startswith(sp): 11 | rel_p = p[len(sp):len(p)] 12 | #print(rel_p) 13 | return dp + rel_p 14 | # dst -> src 15 | if path.startswith(dp): 16 | rel_p = p[len(dp):len(p)] 17 | return sp + rel_p 18 | return dp + p 19 | 20 | def is_image_file(path): 21 | img_exts = ['.jpg','.jpeg','.gif','.png','.bmp'] 22 | _, ext = os.path.splitext(path) 23 | ext = ext.lower() 24 | return ext in img_exts or ext == '' 25 | 26 | 27 | def makedirs(path): 28 | dir,fname = os.path.split(path) 29 | if not os.path.exists(dir): 30 | try: 31 | os.makedirs(dir) 32 | except: 33 | pass 34 | 35 | 36 | def file_walker(dir,visitor): 37 | ''' 38 | Recursive walk through a dir 39 | ''' 40 | filenames = os.listdir(dir) 41 | for filename in filenames: 42 | fullpath = os.path.join(dir,filename) 43 | if os.path.isdir(fullpath): 44 | file_walker(fullpath, visitor) 45 | elif os.path.isfile(fullpath): 46 | visitor.process(fullpath) 47 | 48 | 49 | def read_lines(path): 50 | list = [] 51 | if not os.path.exists(path): 52 | return list 53 | 54 | with open(path, 'r') as f: 55 | for line in f.readlines(): 56 | list.append(line.strip()) 57 | print('read:%d lines from %s' % (len(list), path)) 58 | return list 59 | 60 | def list_walker(list_path,visitor): 61 | list = read_lines(list_path) 62 | for i in range(len(list)): 63 | path = list[i] 64 | visitor.process(path) 65 | -------------------------------------------------------------------------------- /util/logfile.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | error_log = None 3 | def log_open(path): 4 | global error_log 5 | if error_log: 6 | return 7 | error_log = open(path,'w') 8 | return error_log 9 | 10 | def log_write(img_path): 11 | global error_log 12 | if error_log: 13 | error_log.write(img_path+'\n') 14 | error_log.flush() 15 | 16 | def log_close(): 17 | global error_log 18 | error_log.close() 19 | error_log = None --------------------------------------------------------------------------------