├── Feature_Learning
├── README.md
├── feature_expansion
│ ├── data
│ │ ├── query_new.txt
│ │ └── test_track_id.txt
│ ├── feature_concat.py
│ ├── feature_expansion.py
│ ├── gallery_feature.py
│ ├── query_expansion.py
│ ├── query_expansion_stamp.py
│ ├── stamp
│ │ ├── frameGallery.npy
│ │ ├── frameQuery.npy
│ │ ├── g_index_s02.npy
│ │ ├── g_index_s05.npy
│ │ ├── gallery_camera_inf.npy
│ │ ├── orisGallery.npy
│ │ ├── orisQuery.npy
│ │ ├── q_cams.npy
│ │ ├── q_index_s02.npy
│ │ └── q_index_s05.npy
│ └── use_stamps.py
└── learning_model
│ ├── config
│ ├── __init__.py
│ └── defaults.py
│ ├── configs
│ ├── softmax_triplet_VR.yml
│ ├── softmax_triplet_VR_test.yml
│ └── softmax_triplet_VeRi.yml
│ ├── data
│ ├── __init__.py
│ ├── build.py
│ ├── collate_batch.py
│ ├── datasets
│ │ ├── VR.py
│ │ ├── VR_test.py
│ │ ├── VeRi.py
│ │ ├── __init__.py
│ │ ├── bases.py
│ │ ├── cuhk03.py
│ │ ├── dataset_loader.py
│ │ ├── dukemtmcreid.py
│ │ ├── eval_reid.py
│ │ ├── market1501.py
│ │ └── ranking.py
│ ├── samplers
│ │ ├── __init__.py
│ │ └── triplet_sampler.py
│ └── transforms
│ │ ├── __init__.py
│ │ ├── build.py
│ │ └── transforms.py
│ ├── engine
│ ├── __init__.py
│ ├── __init__.pyc
│ ├── __pycache__
│ │ ├── __init__.cpython-37.pyc
│ │ ├── inference.cpython-37.pyc
│ │ └── trainer.cpython-37.pyc
│ ├── inference.py
│ ├── inference.pyc
│ ├── trainer.py
│ └── trainer.pyc
│ ├── layers
│ ├── GHMC_Loss.py
│ ├── LabelSmoothing.py
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── GHMC_Loss.cpython-37.pyc
│ │ ├── LabelSmoothing.cpython-37.pyc
│ │ ├── __init__.cpython-37.pyc
│ │ └── triplet_loss.cpython-37.pyc
│ └── triplet_loss.py
│ ├── modeling
│ ├── __init__.py
│ ├── backbones
│ │ ├── __init__.py
│ │ └── torchvision_models.py
│ └── baseline_de.py
│ ├── solver
│ ├── __init__.py
│ ├── __init__.pyc
│ ├── __pycache__
│ │ ├── __init__.cpython-37.pyc
│ │ ├── build.cpython-37.pyc
│ │ └── lr_scheduler.cpython-37.pyc
│ ├── build.py
│ ├── build.pyc
│ ├── lr_scheduler.py
│ └── lr_scheduler.pyc
│ ├── tests
│ ├── __init__.py
│ └── lr_scheduler_test.py
│ ├── tools
│ ├── __init__.py
│ ├── test.py
│ ├── train.py
│ └── update.py
│ └── utils
│ ├── __init__.py
│ ├── __pycache__
│ ├── __init__.cpython-37.pyc
│ ├── iotools.cpython-37.pyc
│ ├── logger.cpython-37.pyc
│ ├── model_loder.cpython-37.pyc
│ ├── re_ranking.cpython-37.pyc
│ └── reid_metric.cpython-37.pyc
│ ├── iotools.py
│ ├── logger.py
│ ├── model_loder.py
│ ├── re_ranking.py
│ └── reid_metric.py
├── LICENSE
└── README.md
/Feature_Learning/README.md:
--------------------------------------------------------------------------------
1 | # Vehicle ReID_baseline
2 | Baseline model (with bottleneck) for vehicle ReID (using softmax and triplet loss).
3 |
4 | ## learning model
5 | This part is for learning feature extractor. The code is modified form [reid_baseline](https://github.com/L1aoXingyu/reid_baseline), you can check each folder's purpose by yourself.
6 |
7 | ------------
8 |
9 |
10 | **TRAIN AND TEST ON VERI DATASET**
11 | #### Train
12 | `CUDA_VISIBLE_DEVICES=0 python3 tools/train.py --config_file='configs/softmax_triplet_VeRi.yml' MODEL.NAME 'densenet121' `
13 | #### Test
14 | `CUDA_VISIBLE_DEVICES=1 python3 tools/test.py --config_file='configs/softmax_triplet_VeRi.yml' TEST.WEIGHT './CHECKPOINTS/VeRi/softmax_triplet/XX.pth' MODEL.NAME 'densenet121' `
15 |
16 | ------------
17 |
18 |
19 | **TRAIN AND TEST ON AICITY DATASET**
20 | #### Train
21 | The dataloader is in *./data/datasets/VR.py*.
22 | During the training, the test dataset is unavailable, we adopt the test dataset of Veri as the validation. This means that training a model on Aicity and testing it on Veri.
23 | `CUDA_VISIBLE_DEVICES=0 python3 tools/train.py --config_file='configs/softmax_triplet_VR.yml' MODEL.NAME 'densenet121' `
24 | #### Test
25 | Extract the feature representations of test images of Aicity dataset.
26 | `CUDA_VISIBLE_DEVICES=0 python3 tools/update.py --config_file='configs/softmax_triplet_VR_test.yml' TEST.WEIGHT './CHECKPOINTS/VR/softmax_triplet/XX.pth' MODEL.NAME 'densenet121'`
27 |
28 | ------------
29 |
30 |
31 | **MODEL_ENSEMBLE (AICITY)**
32 | To further improve the discriminative ability of features, we adopt model ensemble method.
33 | ##### 1. Model1
34 | Train model with default settings.
35 | ###### *train:*
36 | `CUDA_VISIBLE_DEVICES=0 python3 tools/train.py --config_file='configs/softmax_triplet_VR.yml' MODEL.NAME 'densenet121' OUTPUT_DIR "./CHECKPOINTS/VR/model1"`
37 | ###### *test:*
38 | `CUDA_VISIBLE_DEVICES=0 python3 tools/update.py --config_file='configs/softmax_triplet_VR_test.yml' TEST.WEIGHT './CHECKPOINTS/VR/model1/XX.pth' MODEL.NAME 'densenet121' TEST.QF_NAME 'qf_1' TEST.GF_NAME 'gf_1'`
39 | ##### 2. Model2
40 | Train model with extra data augmentation (COLORJITTER).
41 | ###### *train:*
42 | `CUDA_VISIBLE_DEVICES=0 python3 tools/train.py --config_file='configs/softmax_triplet_VR.yml' MODEL.NAME 'densenet121' OUTPUT_DIR "./CHECKPOINTS/VR/model2" INPUT.COLORJITTER 'True'`
43 | ###### *test:*
44 | `CUDA_VISIBLE_DEVICES=0 python3 tools/update.py --config_file='configs/softmax_triplet_VR_test.yml' TEST.WEIGHT './CHECKPOINTS/VR/model2/XX.pth' MODEL.NAME 'densenet121' INPUT.COLORJITTER 'True' TEST.QF_NAME 'qf_2' TEST.GF_NAME 'gf_2'`
45 | ##### 3. Model3
46 | Use softmargin for the triplet loss.
47 | ###### *train:*
48 | `CUDA_VISIBLE_DEVICES=0 python3 tools/train.py --config_file='configs/softmax_triplet_VR.yml' MODEL.NAME 'densenet121' OUTPUT_DIR "./CHECKPOINTS/VR/model3" DATALOADER.SOFT_MARGIN 'True'`
49 | ###### *test:*
50 | `CUDA_VISIBLE_DEVICES=0 python3 tools/update.py --config_file='configs/softmax_triplet_VR_test.yml' TEST.WEIGHT './CHECKPOINTS/VR/model3/XX.pth' MODEL.NAME 'densenet121' TEST.QF_NAME 'qf_3' TEST.GF_NAME 'gf_3'`
51 | ##### 4. Concatenate
52 | The features of three models are saved in './feature_expansion/data/'.
53 | `python feature_concat.py`
54 | ## Feature expansion
55 | This part consists of gallery expansion and query expansion.
56 | ##### gallery
57 | `python3 gallery_feature.py `
58 | ##### Train
59 | `python3 query_expansion.py `
60 |
--------------------------------------------------------------------------------
/Feature_Learning/feature_expansion/data/query_new.txt:
--------------------------------------------------------------------------------
1 | 000346.jpg
2 | 000901.jpg
3 | 000003.jpg
4 | 000510.jpg
5 | 000458.jpg
6 | 001038.jpg
7 | 000561.jpg
8 | 000572.jpg
9 | 000009.jpg
10 | 000010.jpg
11 | 000011.jpg
12 | 000012.jpg
13 | 000180.jpg
14 | 000014.jpg
15 | 000015.jpg
16 | 000016.jpg
17 | 000554.jpg
18 | 001011.jpg
19 | 000376.jpg
20 | 000078.jpg
21 | 000058.jpg
22 | 000022.jpg
23 | 000902.jpg
24 | 000155.jpg
25 | 000025.jpg
26 | 000480.jpg
27 | 000027.jpg
28 | 000091.jpg
29 | 000029.jpg
30 | 000733.jpg
31 | 000031.jpg
32 | 000276.jpg
33 | 000090.jpg
34 | 000282.jpg
35 | 001005.jpg
36 | 000036.jpg
37 | 000687.jpg
38 | 000262.jpg
39 | 000094.jpg
40 | 000984.jpg
41 | 000041.jpg
42 | 000949.jpg
43 | 000988.jpg
44 | 000958.jpg
45 | 000045.jpg
46 | 000197.jpg
47 | 000047.jpg
48 | 000048.jpg
49 | 000426.jpg
50 | 000402.jpg
51 | 000036.jpg
52 | 000052.jpg
53 | 000864.jpg
54 | 000260.jpg
55 | 000055.jpg
56 | 000056.jpg
57 | 000554.jpg
58 | 000058.jpg
59 | 000999.jpg
60 | 000060.jpg
61 | 000413.jpg
62 | 000564.jpg
63 | 000720.jpg
64 | 000015.jpg
65 | 000065.jpg
66 | 000880.jpg
67 | 000097.jpg
68 | 000525.jpg
69 | 000542.jpg
70 | 000350.jpg
71 | 000276.jpg
72 | 000072.jpg
73 | 000073.jpg
74 | 000074.jpg
75 | 000265.jpg
76 | 000902.jpg
77 | 000572.jpg
78 | 000078.jpg
79 | 001041.jpg
80 | 000080.jpg
81 | 000083.jpg
82 | 000085.jpg
83 | 000083.jpg
84 | 000660.jpg
85 | 000085.jpg
86 | 001009.jpg
87 | 000588.jpg
88 | 000088.jpg
89 | 000089.jpg
90 | 000090.jpg
91 | 000091.jpg
92 | 000505.jpg
93 | 000093.jpg
94 | 000094.jpg
95 | 000282.jpg
96 | 001016.jpg
97 | 000097.jpg
98 | 000243.jpg
99 | 000592.jpg
100 | 000100.jpg
101 | 000101.jpg
102 | 000102.jpg
103 | 000985.jpg
104 | 000720.jpg
105 | 000936.jpg
106 | 000106.jpg
107 | 000090.jpg
108 | 000672.jpg
109 | 000109.jpg
110 | 000340.jpg
111 | 000340.jpg
112 | 000112.jpg
113 | 000113.jpg
114 | 000114.jpg
115 | 001043.jpg
116 | 000116.jpg
117 | 000117.jpg
118 | 000981.jpg
119 | 000119.jpg
120 | 000698.jpg
121 | 000699.jpg
122 | 000909.jpg
123 | 000123.jpg
124 | 000885.jpg
125 | 000125.jpg
126 | 000126.jpg
127 | 000367.jpg
128 | 000217.jpg
129 | 000647.jpg
130 | 000768.jpg
131 | 000131.jpg
132 | 000828.jpg
133 | 000739.jpg
134 | 000134.jpg
135 | 000416.jpg
136 | 000510.jpg
137 | 000244.jpg
138 | 000047.jpg
139 | 000885.jpg
140 | 000898.jpg
141 | 000517.jpg
142 | 000651.jpg
143 | 000047.jpg
144 | 000844.jpg
145 | 000145.jpg
146 | 000828.jpg
147 | 000816.jpg
148 | 000362.jpg
149 | 000762.jpg
150 | 000886.jpg
151 | 000699.jpg
152 | 000012.jpg
153 | 000902.jpg
154 | 000277.jpg
155 | 000155.jpg
156 | 000156.jpg
157 | 000854.jpg
158 | 000097.jpg
159 | 000159.jpg
160 | 000943.jpg
161 | 000161.jpg
162 | 000680.jpg
163 | 000829.jpg
164 | 000510.jpg
165 | 000165.jpg
166 | 000848.jpg
167 | 000125.jpg
168 | 000773.jpg
169 | 000169.jpg
170 | 000116.jpg
171 | 000434.jpg
172 | 000542.jpg
173 | 000803.jpg
174 | 000517.jpg
175 | 000415.jpg
176 | 000176.jpg
177 | 000936.jpg
178 | 000091.jpg
179 | 000179.jpg
180 | 000180.jpg
181 | 000089.jpg
182 | 000591.jpg
183 | 000011.jpg
184 | 000220.jpg
185 | 000554.jpg
186 | 000186.jpg
187 | 000271.jpg
188 | 000810.jpg
189 | 000776.jpg
190 | 000190.jpg
191 | 000626.jpg
192 | 000058.jpg
193 | 000048.jpg
194 | 000556.jpg
195 | 000058.jpg
196 | 000196.jpg
197 | 000197.jpg
198 | 000330.jpg
199 | 000480.jpg
200 | 000902.jpg
201 | 000201.jpg
202 | 000202.jpg
203 | 000485.jpg
204 | 000413.jpg
205 | 000324.jpg
206 | 001033.jpg
207 | 000389.jpg
208 | 000208.jpg
209 | 000209.jpg
210 | 000839.jpg
211 | 000211.jpg
212 | 000212.jpg
213 | 000197.jpg
214 | 000344.jpg
215 | 000331.jpg
216 | 000896.jpg
217 | 000217.jpg
218 | 000413.jpg
219 | 000641.jpg
220 | 000220.jpg
221 | 001043.jpg
222 | 000222.jpg
223 | 000223.jpg
224 | 000224.jpg
225 | 000225.jpg
226 | 000029.jpg
227 | 000367.jpg
228 | 000224.jpg
229 | 000339.jpg
230 | 001016.jpg
231 | 000244.jpg
232 | 000232.jpg
233 | 000233.jpg
234 | 000500.jpg
235 | 000641.jpg
236 | 000558.jpg
237 | 000586.jpg
238 | 000774.jpg
239 | 000239.jpg
240 | 000055.jpg
241 | 000241.jpg
242 | 000242.jpg
243 | 000243.jpg
244 | 000244.jpg
245 | 000345.jpg
246 | 000657.jpg
247 | 000926.jpg
248 | 000248.jpg
249 | 000012.jpg
250 | 000250.jpg
251 | 000097.jpg
252 | 000252.jpg
253 | 000885.jpg
254 | 000254.jpg
255 | 001033.jpg
256 | 000243.jpg
257 | 000065.jpg
258 | 000258.jpg
259 | 000259.jpg
260 | 000260.jpg
261 | 000776.jpg
262 | 000262.jpg
263 | 000263.jpg
264 | 000376.jpg
265 | 000265.jpg
266 | 000960.jpg
267 | 000267.jpg
268 | 000588.jpg
269 | 000217.jpg
270 | 000270.jpg
271 | 000271.jpg
272 | 000746.jpg
273 | 000958.jpg
274 | 000298.jpg
275 | 000326.jpg
276 | 000276.jpg
277 | 000277.jpg
278 | 000971.jpg
279 | 000810.jpg
280 | 001011.jpg
281 | 000703.jpg
282 | 000282.jpg
283 | 000739.jpg
284 | 000284.jpg
285 | 000285.jpg
286 | 000243.jpg
287 | 000277.jpg
288 | 000971.jpg
289 | 000259.jpg
290 | 000958.jpg
291 | 000119.jpg
292 | 000510.jpg
293 | 000293.jpg
294 | 000186.jpg
295 | 000958.jpg
296 | 000607.jpg
297 | 000326.jpg
298 | 000298.jpg
299 | 000299.jpg
300 | 000967.jpg
301 | 000359.jpg
302 | 000344.jpg
303 | 000379.jpg
304 | 001004.jpg
305 | 000305.jpg
306 | 000416.jpg
307 | 000871.jpg
308 | 000348.jpg
309 | 000243.jpg
310 | 000591.jpg
311 | 000981.jpg
312 | 000208.jpg
313 | 000846.jpg
314 | 000314.jpg
315 | 000536.jpg
316 | 000065.jpg
317 | 000642.jpg
318 | 000217.jpg
319 | 000319.jpg
320 | 000010.jpg
321 | 000436.jpg
322 | 000322.jpg
323 | 000323.jpg
324 | 000324.jpg
325 | 000437.jpg
326 | 000326.jpg
327 | 000058.jpg
328 | 000352.jpg
329 | 000329.jpg
330 | 000330.jpg
331 | 000331.jpg
332 | 000782.jpg
333 | 000729.jpg
334 | 000334.jpg
335 | 000222.jpg
336 | 000811.jpg
337 | 000500.jpg
338 | 000876.jpg
339 | 000339.jpg
340 | 000340.jpg
341 | 000341.jpg
342 | 000342.jpg
343 | 000343.jpg
344 | 000344.jpg
345 | 000345.jpg
346 | 000346.jpg
347 | 000808.jpg
348 | 000348.jpg
349 | 000532.jpg
350 | 000350.jpg
351 | 000047.jpg
352 | 000352.jpg
353 | 000197.jpg
354 | 000112.jpg
355 | 000355.jpg
356 | 000379.jpg
357 | 000209.jpg
358 | 000967.jpg
359 | 000359.jpg
360 | 000348.jpg
361 | 001028.jpg
362 | 000362.jpg
363 | 000225.jpg
364 | 000751.jpg
365 | 000165.jpg
366 | 000949.jpg
367 | 000367.jpg
368 | 000208.jpg
369 | 000369.jpg
370 | 000117.jpg
371 | 000949.jpg
372 | 000961.jpg
373 | 000282.jpg
374 | 000660.jpg
375 | 000561.jpg
376 | 000376.jpg
377 | 000968.jpg
378 | 000794.jpg
379 | 000379.jpg
380 | 000380.jpg
381 | 000585.jpg
382 | 000003.jpg
383 | 000462.jpg
384 | 001028.jpg
385 | 000896.jpg
386 | 001045.jpg
387 | 000387.jpg
388 | 000180.jpg
389 | 000389.jpg
390 | 000981.jpg
391 | 000088.jpg
392 | 000369.jpg
393 | 000102.jpg
394 | 000346.jpg
395 | 000003.jpg
396 | 000549.jpg
397 | 000416.jpg
398 | 000917.jpg
399 | 000552.jpg
400 | 000271.jpg
401 | 000871.jpg
402 | 000402.jpg
403 | 000549.jpg
404 | 000532.jpg
405 | 000505.jpg
406 | 000602.jpg
407 | 000935.jpg
408 | 000880.jpg
409 | 000586.jpg
410 | 000984.jpg
411 | 000415.jpg
412 | 000782.jpg
413 | 000413.jpg
414 | 000462.jpg
415 | 000415.jpg
416 | 000416.jpg
417 | 000088.jpg
418 | 000613.jpg
419 | 000960.jpg
420 | 000453.jpg
421 | 000421.jpg
422 | 000422.jpg
423 | 000525.jpg
424 | 000585.jpg
425 | 000811.jpg
426 | 000426.jpg
427 | 000859.jpg
428 | 000239.jpg
429 | 000022.jpg
430 | 000552.jpg
431 | 000441.jpg
432 | 000723.jpg
433 | 000916.jpg
434 | 000434.jpg
435 | 000102.jpg
436 | 000436.jpg
437 | 000437.jpg
438 | 000962.jpg
439 | 000439.jpg
440 | 000362.jpg
441 | 000441.jpg
442 | 000155.jpg
443 | 000768.jpg
444 | 000444.jpg
445 | 000201.jpg
446 | 000926.jpg
447 | 000052.jpg
448 | 000448.jpg
449 | 000052.jpg
450 | 000641.jpg
451 | 000864.jpg
452 | 000859.jpg
453 | 000453.jpg
454 | 000454.jpg
455 | 000009.jpg
456 | 000241.jpg
457 | 001033.jpg
458 | 000458.jpg
459 | 000459.jpg
460 | 000460.jpg
461 | 000421.jpg
462 | 000462.jpg
463 | 000222.jpg
464 | 000464.jpg
465 | 000467.jpg
466 | 000657.jpg
467 | 000467.jpg
468 | 000350.jpg
469 | 000537.jpg
470 | 000470.jpg
471 | 000434.jpg
472 | 000898.jpg
473 | 000090.jpg
474 | 000047.jpg
475 | 000848.jpg
476 | 000803.jpg
477 | 000871.jpg
478 | 000703.jpg
479 | 000259.jpg
480 | 000480.jpg
481 | 000848.jpg
482 | 000871.jpg
483 | 000585.jpg
484 | 000484.jpg
485 | 000485.jpg
486 | 000517.jpg
487 | 000165.jpg
488 | 000926.jpg
489 | 000022.jpg
490 | 000282.jpg
491 | 000733.jpg
492 | 000900.jpg
493 | 000470.jpg
494 | 000113.jpg
495 | 000755.jpg
496 | 000854.jpg
497 | 000578.jpg
498 | 000498.jpg
499 | 000012.jpg
500 | 000500.jpg
501 | 000501.jpg
502 | 000502.jpg
503 | 000558.jpg
504 | 000169.jpg
505 | 000505.jpg
506 | 001001.jpg
507 | 000379.jpg
508 | 000698.jpg
509 | 001011.jpg
510 | 000510.jpg
511 | 000511.jpg
512 | 000512.jpg
513 | 000998.jpg
514 | 000514.jpg
515 | 000794.jpg
516 | 000926.jpg
517 | 000517.jpg
518 | 000909.jpg
519 | 000519.jpg
520 | 000052.jpg
521 | 000926.jpg
522 | 000522.jpg
523 | 000523.jpg
524 | 000252.jpg
525 | 000525.jpg
526 | 000529.jpg
527 | 000871.jpg
528 | 000233.jpg
529 | 000529.jpg
530 | 000074.jpg
531 | 000531.jpg
532 | 000532.jpg
533 | 000367.jpg
534 | 000239.jpg
535 | 000131.jpg
536 | 000536.jpg
537 | 000537.jpg
538 | 000467.jpg
539 | 000539.jpg
540 | 000458.jpg
541 | 000541.jpg
542 | 000542.jpg
543 | 000448.jpg
544 | 000971.jpg
545 | 000886.jpg
546 | 000389.jpg
547 | 000547.jpg
548 | 000548.jpg
549 | 000549.jpg
550 | 000285.jpg
551 | 000276.jpg
552 | 000552.jpg
553 | 000529.jpg
554 | 000554.jpg
555 | 000555.jpg
556 | 000556.jpg
557 | 000355.jpg
558 | 000558.jpg
559 | 000559.jpg
560 | 000241.jpg
561 | 000561.jpg
562 | 000041.jpg
563 | 000259.jpg
564 | 000564.jpg
565 | 000536.jpg
566 | 000047.jpg
567 | 000886.jpg
568 | 000568.jpg
569 | 001001.jpg
570 | 000525.jpg
571 | 000733.jpg
572 | 000572.jpg
573 | 000389.jpg
574 | 000638.jpg
575 | 000225.jpg
576 | 000576.jpg
577 | 000577.jpg
578 | 000578.jpg
579 | 000547.jpg
580 | 000517.jpg
581 | 000626.jpg
582 | 000582.jpg
583 | 000241.jpg
584 | 000917.jpg
585 | 000585.jpg
586 | 000586.jpg
587 | 000517.jpg
588 | 000588.jpg
589 | 000470.jpg
590 | 000723.jpg
591 | 000591.jpg
592 | 000592.jpg
593 | 000593.jpg
594 | 000211.jpg
595 | 000056.jpg
596 | 001011.jpg
597 | 000597.jpg
598 | 000846.jpg
599 | 000343.jpg
600 | 000600.jpg
601 | 000074.jpg
602 | 000602.jpg
603 | 000376.jpg
604 | 000585.jpg
605 | 000949.jpg
606 | 000606.jpg
607 | 000607.jpg
608 | 000549.jpg
609 | 000743.jpg
610 | 000523.jpg
611 | 000611.jpg
612 | 000498.jpg
613 | 000613.jpg
614 | 000638.jpg
615 | 000576.jpg
616 | 000529.jpg
617 | 001004.jpg
618 | 000334.jpg
619 | 000029.jpg
620 | 000093.jpg
621 | 000556.jpg
622 | 000536.jpg
623 | 000576.jpg
624 | 000554.jpg
625 | 000625.jpg
626 | 000626.jpg
627 | 000999.jpg
628 | 000341.jpg
629 | 000459.jpg
630 | 000586.jpg
631 | 000003.jpg
632 | 000211.jpg
633 | 000220.jpg
634 | 000742.jpg
635 | 000876.jpg
636 | 000636.jpg
637 | 000665.jpg
638 | 000638.jpg
639 | 000657.jpg
640 | 000828.jpg
641 | 000641.jpg
642 | 000642.jpg
643 | 000065.jpg
644 | 000644.jpg
645 | 000645.jpg
646 | 000031.jpg
647 | 000647.jpg
648 | 000648.jpg
649 | 000265.jpg
650 | 000650.jpg
651 | 000651.jpg
652 | 000112.jpg
653 | 001045.jpg
654 | 000712.jpg
655 | 000898.jpg
656 | 000823.jpg
657 | 000657.jpg
658 | 000532.jpg
659 | 001034.jpg
660 | 000660.jpg
661 | 001007.jpg
662 | 000755.jpg
663 | 000742.jpg
664 | 001016.jpg
665 | 000665.jpg
666 | 000464.jpg
667 | 000554.jpg
668 | 000803.jpg
669 | 000510.jpg
670 | 000484.jpg
671 | 000593.jpg
672 | 000672.jpg
673 | 000673.jpg
674 | 000864.jpg
675 | 000379.jpg
676 | 000165.jpg
677 | 000339.jpg
678 | 000339.jpg
679 | 000436.jpg
680 | 000680.jpg
681 | 000324.jpg
682 | 000045.jpg
683 | 000426.jpg
684 | 000684.jpg
685 | 000755.jpg
686 | 000755.jpg
687 | 000687.jpg
688 | 000260.jpg
689 | 000559.jpg
690 | 000690.jpg
691 | 000691.jpg
692 | 000376.jpg
693 | 000949.jpg
694 | 000467.jpg
695 | 000340.jpg
696 | 000696.jpg
697 | 000613.jpg
698 | 000698.jpg
699 | 000699.jpg
700 | 000552.jpg
701 | 000058.jpg
702 | 000348.jpg
703 | 000703.jpg
704 | 000782.jpg
705 | 000578.jpg
706 | 000498.jpg
707 | 000117.jpg
708 | 000556.jpg
709 | 000156.jpg
710 | 000085.jpg
711 | 000254.jpg
712 | 000712.jpg
713 | 000898.jpg
714 | 000212.jpg
715 | 000379.jpg
716 | 000211.jpg
717 | 000606.jpg
718 | 000339.jpg
719 | 000224.jpg
720 | 000720.jpg
721 | 000647.jpg
722 | 000722.jpg
723 | 000723.jpg
724 | 000762.jpg
725 | 000591.jpg
726 | 000699.jpg
727 | 000454.jpg
728 | 000600.jpg
729 | 000729.jpg
730 | 000730.jpg
731 | 000731.jpg
732 | 000732.jpg
733 | 000733.jpg
734 | 000734.jpg
735 | 000735.jpg
736 | 000699.jpg
737 | 000212.jpg
738 | 000738.jpg
739 | 000739.jpg
740 | 001007.jpg
741 | 000060.jpg
742 | 000742.jpg
743 | 000743.jpg
744 | 000270.jpg
745 | 000745.jpg
746 | 000746.jpg
747 | 000917.jpg
748 | 000572.jpg
749 | 000948.jpg
750 | 000348.jpg
751 | 000751.jpg
752 | 000642.jpg
753 | 000859.jpg
754 | 000588.jpg
755 | 000755.jpg
756 | 000864.jpg
757 | 000757.jpg
758 | 000517.jpg
759 | 000334.jpg
760 | 000548.jpg
761 | 000723.jpg
762 | 000762.jpg
763 | 000536.jpg
764 | 000810.jpg
765 | 000585.jpg
766 | 000254.jpg
767 | 000767.jpg
768 | 000768.jpg
769 | 000369.jpg
770 | 000690.jpg
771 | 000885.jpg
772 | 000186.jpg
773 | 000773.jpg
774 | 000774.jpg
775 | 000252.jpg
776 | 000776.jpg
777 | 000458.jpg
778 | 000828.jpg
779 | 000058.jpg
780 | 000780.jpg
781 | 000698.jpg
782 | 000782.jpg
783 | 000380.jpg
784 | 000687.jpg
785 | 000607.jpg
786 | 000786.jpg
787 | 000787.jpg
788 | 000211.jpg
789 | 000500.jpg
790 | 001029.jpg
791 | 000072.jpg
792 | 000341.jpg
793 | 000774.jpg
794 | 000794.jpg
795 | 000029.jpg
796 | 000962.jpg
797 | 000985.jpg
798 | 000116.jpg
799 | 000480.jpg
800 | 000800.jpg
801 | 000703.jpg
802 | 000720.jpg
803 | 000803.jpg
804 | 000453.jpg
805 | 000525.jpg
806 | 000691.jpg
807 | 000607.jpg
808 | 000808.jpg
809 | 000787.jpg
810 | 000810.jpg
811 | 000811.jpg
812 | 000036.jpg
813 | 000131.jpg
814 | 000277.jpg
815 | 000343.jpg
816 | 000816.jpg
817 | 000501.jpg
818 | 000485.jpg
819 | 000819.jpg
820 | 000402.jpg
821 | 001037.jpg
822 | 000822.jpg
823 | 000823.jpg
824 | 000437.jpg
825 | 000572.jpg
826 | 001045.jpg
827 | 000827.jpg
828 | 000828.jpg
829 | 000829.jpg
830 | 000660.jpg
831 | 000690.jpg
832 | 000909.jpg
833 | 000554.jpg
834 | 000834.jpg
835 | 000444.jpg
836 | 000537.jpg
837 | 000822.jpg
838 | 000787.jpg
839 | 000839.jpg
840 | 000917.jpg
841 | 000559.jpg
842 | 000282.jpg
843 | 000843.jpg
844 | 000844.jpg
845 | 000626.jpg
846 | 000846.jpg
847 | 000186.jpg
848 | 000848.jpg
849 | 000027.jpg
850 | 000542.jpg
851 | 000484.jpg
852 | 000564.jpg
853 | 000853.jpg
854 | 000854.jpg
855 | 000277.jpg
856 | 000856.jpg
857 | 000233.jpg
858 | 000606.jpg
859 | 000859.jpg
860 | 000902.jpg
861 | 000755.jpg
862 | 000389.jpg
863 | 000117.jpg
864 | 000864.jpg
865 | 000865.jpg
866 | 000935.jpg
867 | 001034.jpg
868 | 000943.jpg
869 | 000444.jpg
870 | 000293.jpg
871 | 000871.jpg
872 | 000114.jpg
873 | 000505.jpg
874 | 000564.jpg
875 | 000529.jpg
876 | 000876.jpg
877 | 000517.jpg
878 | 000638.jpg
879 | 000359.jpg
880 | 000880.jpg
881 | 000270.jpg
882 | 000085.jpg
883 | 000948.jpg
884 | 000884.jpg
885 | 000885.jpg
886 | 000886.jpg
887 | 000887.jpg
888 | 000094.jpg
889 | 000816.jpg
890 | 000022.jpg
891 | 000787.jpg
892 | 000967.jpg
893 | 000787.jpg
894 | 000277.jpg
895 | 000244.jpg
896 | 000896.jpg
897 | 000897.jpg
898 | 000898.jpg
899 | 000690.jpg
900 | 000900.jpg
901 | 000901.jpg
902 | 000902.jpg
903 | 000031.jpg
904 | 000743.jpg
905 | 000905.jpg
906 | 000703.jpg
907 | 000588.jpg
908 | 001043.jpg
909 | 000909.jpg
910 | 000549.jpg
911 | 001001.jpg
912 | 000271.jpg
913 | 000225.jpg
914 | 000822.jpg
915 | 001004.jpg
916 | 000916.jpg
917 | 000917.jpg
918 | 000334.jpg
919 | 000088.jpg
920 | 000112.jpg
921 | 001033.jpg
922 | 000239.jpg
923 | 000532.jpg
924 | 000924.jpg
925 | 000925.jpg
926 | 000926.jpg
927 | 000179.jpg
928 | 000556.jpg
929 | 000436.jpg
930 | 000738.jpg
931 | 000413.jpg
932 | 000981.jpg
933 | 000803.jpg
934 | 000762.jpg
935 | 000935.jpg
936 | 000936.jpg
937 | 000085.jpg
938 | 000985.jpg
939 | 000755.jpg
940 | 000119.jpg
941 | 000083.jpg
942 | 000680.jpg
943 | 000943.jpg
944 | 000015.jpg
945 | 000434.jpg
946 | 000346.jpg
947 | 000968.jpg
948 | 000948.jpg
949 | 000949.jpg
950 | 000651.jpg
951 | 000774.jpg
952 | 000293.jpg
953 | 000734.jpg
954 | 000348.jpg
955 | 000197.jpg
956 | 000956.jpg
957 | 000962.jpg
958 | 000958.jpg
959 | 000959.jpg
960 | 000960.jpg
961 | 000961.jpg
962 | 000962.jpg
963 | 001011.jpg
964 | 000593.jpg
965 | 000965.jpg
966 | 000774.jpg
967 | 000967.jpg
968 | 000968.jpg
969 | 000948.jpg
970 | 000065.jpg
971 | 000971.jpg
972 | 000607.jpg
973 | 000948.jpg
974 | 000454.jpg
975 | 000041.jpg
976 | 000453.jpg
977 | 000819.jpg
978 | 000626.jpg
979 | 000523.jpg
980 | 000083.jpg
981 | 000981.jpg
982 | 000010.jpg
983 | 000943.jpg
984 | 000984.jpg
985 | 000985.jpg
986 | 000986.jpg
987 | 000415.jpg
988 | 000988.jpg
989 | 001041.jpg
990 | 000990.jpg
991 | 000262.jpg
992 | 000780.jpg
993 | 000993.jpg
994 | 000426.jpg
995 | 000523.jpg
996 | 000998.jpg
997 | 000997.jpg
998 | 000998.jpg
999 | 000999.jpg
1000 | 000243.jpg
1001 | 001001.jpg
1002 | 000720.jpg
1003 | 000459.jpg
1004 | 001004.jpg
1005 | 001005.jpg
1006 | 000480.jpg
1007 | 001007.jpg
1008 | 000329.jpg
1009 | 001009.jpg
1010 | 001010.jpg
1011 | 001011.jpg
1012 | 000556.jpg
1013 | 000402.jpg
1014 | 000448.jpg
1015 | 000985.jpg
1016 | 001016.jpg
1017 | 001017.jpg
1018 | 000762.jpg
1019 | 000665.jpg
1020 | 000340.jpg
1021 | 000638.jpg
1022 | 000880.jpg
1023 | 000012.jpg
1024 | 000426.jpg
1025 | 000380.jpg
1026 | 000720.jpg
1027 | 000558.jpg
1028 | 001028.jpg
1029 | 001029.jpg
1030 | 000262.jpg
1031 | 000532.jpg
1032 | 000871.jpg
1033 | 001033.jpg
1034 | 001034.jpg
1035 | 001035.jpg
1036 | 001036.jpg
1037 | 001037.jpg
1038 | 001038.jpg
1039 | 001039.jpg
1040 | 000738.jpg
1041 | 001041.jpg
1042 | 000458.jpg
1043 | 001043.jpg
1044 | 000738.jpg
1045 | 001045.jpg
1046 | 000819.jpg
1047 | 000319.jpg
1048 | 000917.jpg
1049 | 000117.jpg
1050 | 000738.jpg
1051 | 001051.jpg
1052 | 000201.jpg
--------------------------------------------------------------------------------
/Feature_Learning/feature_expansion/feature_concat.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Created on Sat Apr 27 15:03:13 2019
4 |
5 | @author: Deng
6 | """
7 |
8 | import numpy as np
9 |
10 | #--------------------------- load feature -----------------#
11 | # load feature
12 | gf_1 = np.load('./data/gf_1.npy')
13 | gf_1_n = np.linalg.norm(gf_1, axis=1, keepdims=True)
14 | gf_1 = gf_1 / gf_1_n
15 |
16 | qf_1 = np.load('./data/qf_1.npy')
17 | qf_1_n = np.linalg.norm(qf_1, axis=1, keepdims=True)
18 | qf_1 = qf_1 / qf_1_n
19 |
20 | # model 2
21 | gf_2 = np.load('./data/gf_2.npy')
22 | gf_2_n = np.linalg.norm(gf_2, axis=1, keepdims=True)
23 | gf_2 = gf_2 / gf_2_n
24 |
25 | qf_2 = np.load('./data/qf_2.npy')
26 | qf_2_n = np.linalg.norm(qf_2, axis=1, keepdims=True)
27 | qf_2 = qf_2 / qf_2_n
28 |
29 | # model 3
30 | gf_3 = np.load('./data/gf_3.npy')
31 | gf_3_n = np.linalg.norm(gf_3, axis=1, keepdims=True)
32 | gf_3 = gf_3 / gf_3_n
33 |
34 | qf_3 = np.load('./data/qf_3.npy')
35 | qf_3_n = np.linalg.norm(qf_3, axis=1, keepdims=True)
36 | qf_3 = qf_3 / qf_3_n
37 |
38 | #--------------------------- feature concat -----------------#
39 | qf_ori = np.concatenate((qf_1, qf_2, qf_3), axis=1) /np.sqrt(3)
40 | gf_ori = np.concatenate((gf_1, gf_2, gf_3), axis=1) /np.sqrt(3)
41 |
42 | #--------------------------- save feature -----------------#
43 | np.save('./data/qf_ori.npy', qf_ori)
44 | np.save('./data/gf_ori.npy', gf_ori)
45 |
--------------------------------------------------------------------------------
/Feature_Learning/feature_expansion/feature_expansion.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Created on Sat Apr 27 15:03:13 2019
4 |
5 | @author: PAMI Deng
6 | """
7 |
8 | import numpy as np
9 | import copy
10 |
11 |
12 | # frame inforamtion
13 | frameQuery = np.load('./data/frameQuery.npy')
14 | frameTracklets = np.load('./data/frameGallery.npy')
15 | frameGallery = np.zeros([18290])
16 |
17 | # tracklet name with ID
18 | g_name = []
19 | f = open('./test_track_id.txt', 'r')
20 | for k, line in enumerate(f):
21 | temp = list(map(int, line.split(' ')[:-1]))
22 | g_name.append(list(map(lambda x: x-1, temp)))
23 | for indexTemp, idTemp in enumerate(temp):
24 | frameGallery[idTemp-1] = frameTracklets[k]
25 | f.close
26 |
27 | # gallery labels and query labels
28 | q_label = np.ones([1052])*1000
29 | g_label = np.ones([18290])*1000
30 |
31 | # camera inforamation
32 | q_cams = np.load('./data/q_cams.npy')
33 | g_cams = np.load('./data/gallery_camera_inf.npy')
34 |
35 | # open results of S02
36 | f = open('./data/s02_query_gallery.txt', 'r')
37 | for k, line in enumerate(f):
38 | temp = line.split(' : ')
39 | temp0 = list(map(int, temp[0].split(' ')))
40 | q_label[list(map(lambda x: x-1, temp0))] = int(k)
41 |
42 | temp1 = list(map(int, temp[1].split(' ')))
43 | temp2 = list(map(lambda x: x-1, temp1))
44 | for i in range(len(temp2)):
45 | g_label[np.array(g_name)[temp2[i]]] = int(k)
46 | f.close()
47 |
48 | q_index = np.nonzero(q_label!=1000)[0]
49 | g_index = np.nonzero(g_label!=1000)[0]
50 |
51 | #-------------------------------------- query expansion version 1 -------------------------#
52 | # load feature
53 | gf = np.load('./data/gf_multi.npy')
54 | qf = np.load('./data/qf_multi.npy')
55 | #dist = np.load('./data/distmat.npy')
56 |
57 | dist = np.dot(qf, np.transpose(gf))
58 | dist = 2. - 2 * dist # change the cosine similarity metric to euclidean similarity metric
59 | d_max = 10.0
60 |
61 | # time filter
62 | frameGap = 190
63 | for i in range(len(q_index)):
64 | key = q_index[i]
65 | indice = abs(frameGallery - frameQuery[key])> frameGap
66 | if q_cams[key]==6:
67 | indice = indice | (abs(frameGallery - frameQuery[key])> 60) & (g_cams == 9)
68 | elif q_cams[key] == 9:
69 | indice = indice | (abs(frameGallery - frameQuery[key])> 50) & (g_cams == 6)
70 | indice = np.nonzero(indice)[0]
71 | dist[key][indice] = d_max
72 |
73 | # camera filter for S02 and S05
74 | for i in range(len(dist)):
75 | indice = np.nonzero((g_cams == q_cams[i]))[0]
76 | dist[i][indice] = d_max
77 |
78 | # scene filter for S02
79 | g_indice_scene = np.nonzero(g_label==1000)[0] #S05 indice
80 | for i in range(len(q_index)):
81 | key = q_index[i]
82 | dist[key][g_indice_scene] = d_max
83 |
84 | # scene filter for S05
85 | g_indice_scene = np.nonzero(g_label!=1000)[0] #S02 indice
86 | s05_indice = np.nonzero(q_label==1000)[0]
87 | for i in range(len(s05_indice)):
88 | key = s05_indice[i]
89 | dist[key][g_indice_scene] = d_max
90 |
91 | #---------------------------- query expansion ----------------------------#
92 | qf_new = []
93 | T = 9
94 | num = 1
95 | d_max = 10.0
96 |
97 | for t in range(num):
98 | qf_new = []
99 | for i in range(len(dist)):
100 | indice = np.argsort(dist[i])[:T]
101 | temp = np.concatenate((qf[i][np.newaxis, :], gf[indice]), axis=0)
102 | #temp = gf[indice]
103 | qf_new.append(np.mean(temp, axis=0, keepdims=True))
104 | qf = np.squeeze(np.array(qf_new))
105 | # feature norm
106 | q_n = np.linalg.norm(qf, axis=1, keepdims=True)
107 | qf = qf / q_n
108 |
109 | dist = np.dot(qf, np.transpose(gf))
110 | dist = 2. - 2 * dist # change the cosine similarity metric to euclidean similarity metric
111 | #np.save('./data/gf.npy', gf)
112 | np.save('./data/qf_new_%d.npy' % t, qf)
113 |
114 | # time filter
115 | frameGap = 190
116 | for i in range(len(q_index)):
117 | key = q_index[i]
118 | indice = abs(frameGallery - frameQuery[key])> frameGap
119 | if q_cams[key]==6:
120 | indice = indice | (abs(frameGallery - frameQuery[key])> 60) & (g_cams == 9)
121 | elif q_cams[key] == 9:
122 | indice = indice | (abs(frameGallery - frameQuery[key])> 50) & (g_cams == 6)
123 | indice = np.nonzero(indice)[0]
124 | dist[key][indice] = d_max
125 |
126 | # camera filter for S02 and S05
127 | for i in range(len(dist)):
128 | indice = np.nonzero((g_cams == q_cams[i]))[0]
129 | dist[i][indice] = d_max
130 |
131 | # scene filter for S02
132 | g_indice_scene = np.nonzero(g_label==1000)[0] #S05 indice
133 | for i in range(len(q_index)):
134 | key = q_index[i]
135 | dist[key][g_indice_scene] = d_max
136 |
137 | # scene filter for S05
138 | g_indice_scene = np.nonzero(g_label!=1000)[0] #S02 indice
139 | s05_indice = np.nonzero(q_label==1000)[0]
140 | for i in range(len(s05_indice)):
141 | key = s05_indice[i]
142 | dist[key][g_indice_scene] = d_max
143 |
144 | '''
145 | #-------------------------------------- query expansion version 2 -------------------------#
146 | # load feature
147 | gf = np.load('./data/gf_multi.npy')
148 | qf = np.load('./data/qf_multi.npy')
149 |
150 | f = open('./results/track2_time_all_order.txt', 'r')
151 | dist = []
152 |
153 | for line in f:
154 | temp0 = list(map(int, line.strip(' \n').split(' ')))
155 | temp = list(map(lambda x: x-1, temp0))
156 | dist.append(temp)
157 |
158 | dist = np.array(dist)
159 | dist = np.load('./data/distmat.npy')
160 | qf_new = []
161 | T = 10
162 | weights = 1
163 |
164 | for i in range(len(dist)):
165 | indice = np.argsort(dist[i])[:T]
166 | #temp = gf[indice]
167 | temp = np.mean(gf[indice], axis=0, keepdims=True)
168 | temp = np.concatenate((qf[i][np.newaxis, :], temp), axis=0)
169 | qf_new.append(np.mean(temp, axis=0, keepdims=True))
170 | qf = np.squeeze(np.array(qf_new))
171 | # feature norm
172 | q_n = np.linalg.norm(qf, axis=1, keepdims=True)
173 | qf = qf / q_n
174 |
175 | dist = np.dot(qf, np.transpose(gf))
176 | dist = 2. - 2 * dist # change the cosine similarity metric to euclidean similarity metric
177 | #np.save('./data/gf.npy', gf)
178 | np.save('./data/qf_new_0.npy', qf)
179 | '''
180 |
--------------------------------------------------------------------------------
/Feature_Learning/feature_expansion/gallery_feature.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Created on Sat Apr 27 15:03:13 2019
4 |
5 | @author: Deng
6 | """
7 |
8 | import numpy as np
9 | import copy
10 | from sklearn.decomposition import PCA
11 |
12 |
13 | def softmax(x):
14 | """Compute the softmax in a numerically stable way."""
15 | x = x - np.max(x)
16 | exp_x = np.exp(x)
17 | softmax_x = exp_x / np.sum(exp_x)
18 | return softmax_x
19 |
20 | # load feature
21 | gf = np.load('./data/gf_ori.npy')
22 |
23 | # tracklet name with ID
24 | track_name = []
25 | f = open('./data/test_track_id.txt', 'r')
26 | for k, line in enumerate(f):
27 | temp = list(map(int, line.split(' ')[:-1]))
28 | track_name.append(list(map(lambda x: x-1, temp)))
29 | f.close
30 |
31 | # re-organize gallery feature
32 | T=6 #6
33 | for i in range(len(track_name)):
34 | indice = track_name[i]
35 | for j in range(0, len(indice), T):
36 | if (j+T)>len(indice):
37 | ind = indice[j:]
38 | else:
39 | ind = indice[j:j+T]
40 | gf_temp = np.mean(gf[ind], axis=0, keepdims=True)
41 | gf[ind] = gf_temp
42 |
43 | # feature norm
44 | g_n = np.linalg.norm(gf, axis=1, keepdims=True)
45 | gf = gf / g_n
46 |
47 | '''
48 | # PCA for feature
49 | pca=PCA(n_components=1024)
50 | gf_new = pca.fit_transform(gf)
51 | qf_new = pca.transform(qf)
52 | '''
53 | np.save('./data/gf_multi.npy', gf)
54 |
--------------------------------------------------------------------------------
/Feature_Learning/feature_expansion/query_expansion.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Created on Sat Apr 27 15:03:13 2019
4 |
5 | @author: Deng
6 | """
7 |
8 | import numpy as np
9 |
10 |
11 | #--------------------------- query expansion -----------------#
12 | # load feature
13 | gf = np.load('./data/gf_multi.npy')
14 | qf = np.load('./data/qf_ori.npy')
15 |
16 | # load indice
17 | qf_new = np.load('./data/qf_ori.npy')
18 | query_index = []
19 | f = open('./data/query_new.txt', 'r')
20 | for k, line in enumerate(f):
21 | temp = int(line[0:6]) - 1
22 | query_index.append(temp)
23 | qf[k] = qf_new[temp]
24 | f.close()
25 |
26 | # feature norm
27 | q_n = np.linalg.norm(qf, axis=1, keepdims=True)
28 | qf = qf / q_n
29 |
30 | dist = np.dot(qf, np.transpose(gf))
31 | dist = 2. - 2 * dist # change the cosine similarity metric to euclidean similarity metric
32 |
33 | qf_new = []
34 | T = 9
35 | num = 1
36 | d_max = 10.0
37 |
38 | for t in range(num):
39 | qf_new = []
40 | for i in range(len(dist)):
41 | indice = np.argsort(dist[i])[:T]
42 | temp = np.concatenate((qf[i][np.newaxis, :], gf[indice]), axis=0)
43 | qf_new.append(np.mean(temp, axis=0, keepdims=True))
44 |
45 | qf = np.squeeze(np.array(qf_new))
46 | # feature norm
47 | q_n = np.linalg.norm(qf, axis=1, keepdims=True)
48 | qf = qf / q_n
49 |
50 | dist = np.dot(qf, np.transpose(gf))
51 | dist = 2. - 2 * dist # change the cosine similarity metric to euclidean similarity metric
52 | np.save('./data/qf_multi_%d.npy' % t, qf)
53 |
--------------------------------------------------------------------------------
/Feature_Learning/feature_expansion/query_expansion_stamp.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Created on Sat Apr 27 15:03:13 2019
4 |
5 | @author: Deng
6 | """
7 |
8 | import numpy as np
9 |
10 |
11 | # frame inforamtion
12 | frameQuery = np.load('./stamp/frameQuery.npy')
13 | frameTracklets = np.load('./stamp/frameGallery.npy')
14 | frameGallery = np.zeros([18290])
15 |
16 | # tracklet name with ID
17 | g_name = []
18 | f = open('./data/test_track_id.txt', 'r')
19 | for k, line in enumerate(f):
20 | temp = list(map(int, line.split(' ')[:-1]))
21 | g_name.append(list(map(lambda x: x-1, temp)))
22 | for indexTemp, idTemp in enumerate(temp):
23 | frameGallery[idTemp-1] = frameTracklets[k]
24 | f.close
25 |
26 | # camera inforamation
27 | q_cams = np.load('./stamp/q_cams.npy')
28 | g_cams = np.load('./stamp/gallery_camera_inf.npy')
29 |
30 | # location information
31 | g_index_s05 = np.load('./stamp/g_index_s05.npy')
32 | q_index_s05 = np.load('./stamp/q_index_s05.npy')
33 |
34 | q_index = np.load('./stamp/q_index_s02.npy')
35 | g_index = np.load('./stamp/g_index_s02.npy')
36 |
37 | #--------------- query expansion with location and time info --------------#
38 | # load feature
39 | gf = np.load('./data/gf_multi.npy')
40 | qf = np.load('./data/qf_multi.npy')
41 |
42 | dist = np.dot(qf, np.transpose(gf))
43 | dist = 2. - 2 * dist # change the cosine similarity metric to euclidean similarity metric
44 | d_max = 10.0
45 |
46 | # time filter
47 | frameGap = 190
48 | for i in range(len(q_index)):
49 | key = q_index[i]
50 | indice = abs(frameGallery - frameQuery[key])> frameGap
51 | if q_cams[key]==6:
52 | indice = indice | (abs(frameGallery - frameQuery[key])> 60) & (g_cams == 9)
53 | elif q_cams[key] == 9:
54 | indice = indice | (abs(frameGallery - frameQuery[key])> 50) & (g_cams == 6)
55 | indice = np.nonzero(indice)[0]
56 | dist[key][indice] = d_max
57 |
58 | # camera filter for S02 and S05
59 | for i in range(len(dist)):
60 | indice = np.nonzero((g_cams == q_cams[i]))[0]
61 | dist[i][indice] = d_max
62 |
63 | # scene filter for S02
64 | g_indice_scene = g_index_s05 #S05 indice
65 | for i in range(len(q_index)):
66 | key = q_index[i]
67 | dist[key][g_indice_scene] = d_max
68 |
69 | # scene filter for S05
70 | g_indice_scene = g_index #S02 indice
71 | s05_indice = q_index_s05
72 | for i in range(len(s05_indice)):
73 | key = s05_indice[i]
74 | dist[key][g_indice_scene] = d_max
75 |
76 | #---------------------------- query expansion ----------------------------#
77 | qf_new = []
78 | T = 9
79 |
80 | qf_new = []
81 | for i in range(len(dist)):
82 | indice = np.argsort(dist[i])[:T]
83 | temp = np.concatenate((qf[i][np.newaxis, :], gf[indice]), axis=0)
84 | #temp = gf[indice]
85 | qf_new.append(np.mean(temp, axis=0, keepdims=True))
86 | qf = np.squeeze(np.array(qf_new))
87 | # feature norm
88 | q_n = np.linalg.norm(qf, axis=1, keepdims=True)
89 | qf = qf / q_n
90 |
91 | dist = np.dot(qf, np.transpose(gf))
92 | dist = 2. - 2 * dist # change the cosine similarity metric to euclidean similarity metric
93 | #np.save('./data/gf.npy', gf)
94 | np.save('./data/qf_new.npy', qf)
95 |
--------------------------------------------------------------------------------
/Feature_Learning/feature_expansion/stamp/frameGallery.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Simon4Yan/feature_learning/23ecc1bb2ce3ce4bece9159ca4ecc420e3e8f34c/Feature_Learning/feature_expansion/stamp/frameGallery.npy
--------------------------------------------------------------------------------
/Feature_Learning/feature_expansion/stamp/frameQuery.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Simon4Yan/feature_learning/23ecc1bb2ce3ce4bece9159ca4ecc420e3e8f34c/Feature_Learning/feature_expansion/stamp/frameQuery.npy
--------------------------------------------------------------------------------
/Feature_Learning/feature_expansion/stamp/g_index_s02.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Simon4Yan/feature_learning/23ecc1bb2ce3ce4bece9159ca4ecc420e3e8f34c/Feature_Learning/feature_expansion/stamp/g_index_s02.npy
--------------------------------------------------------------------------------
/Feature_Learning/feature_expansion/stamp/g_index_s05.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Simon4Yan/feature_learning/23ecc1bb2ce3ce4bece9159ca4ecc420e3e8f34c/Feature_Learning/feature_expansion/stamp/g_index_s05.npy
--------------------------------------------------------------------------------
/Feature_Learning/feature_expansion/stamp/gallery_camera_inf.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Simon4Yan/feature_learning/23ecc1bb2ce3ce4bece9159ca4ecc420e3e8f34c/Feature_Learning/feature_expansion/stamp/gallery_camera_inf.npy
--------------------------------------------------------------------------------
/Feature_Learning/feature_expansion/stamp/orisGallery.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Simon4Yan/feature_learning/23ecc1bb2ce3ce4bece9159ca4ecc420e3e8f34c/Feature_Learning/feature_expansion/stamp/orisGallery.npy
--------------------------------------------------------------------------------
/Feature_Learning/feature_expansion/stamp/orisQuery.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Simon4Yan/feature_learning/23ecc1bb2ce3ce4bece9159ca4ecc420e3e8f34c/Feature_Learning/feature_expansion/stamp/orisQuery.npy
--------------------------------------------------------------------------------
/Feature_Learning/feature_expansion/stamp/q_cams.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Simon4Yan/feature_learning/23ecc1bb2ce3ce4bece9159ca4ecc420e3e8f34c/Feature_Learning/feature_expansion/stamp/q_cams.npy
--------------------------------------------------------------------------------
/Feature_Learning/feature_expansion/stamp/q_index_s02.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Simon4Yan/feature_learning/23ecc1bb2ce3ce4bece9159ca4ecc420e3e8f34c/Feature_Learning/feature_expansion/stamp/q_index_s02.npy
--------------------------------------------------------------------------------
/Feature_Learning/feature_expansion/stamp/q_index_s05.npy:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Simon4Yan/feature_learning/23ecc1bb2ce3ce4bece9159ca4ecc420e3e8f34c/Feature_Learning/feature_expansion/stamp/q_index_s05.npy
--------------------------------------------------------------------------------
/Feature_Learning/feature_expansion/use_stamps.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | """
4 | Created on Sat Apr 27 15:03:13 2019
5 |
6 | @author: Lv
7 | """
8 |
9 | import numpy as np
10 | import copy
11 |
12 |
13 | # frame inforamtion
14 | frameQuery = np.load('./stamp/frameQuery.npy')
15 | frameTracklets = np.load('./stamp/frameGallery.npy')
16 | frameGallery = np.zeros([18290]) #18290 is the num of gallery images
17 |
18 | # tracklet name with ID
19 | g_name = []
20 | f = open('./data/test_track_id.txt', 'r')
21 | for k, line in enumerate(f):
22 | temp = list(map(int, line.split(' ')[:-1]))
23 | if len(temp)==1:
24 | continue
25 | g_name.append(list(map(lambda x: x-1, temp)))
26 | for indexTemp, idTemp in enumerate(temp):
27 | frameGallery[idTemp-1] = frameTracklets[k]
28 | f.close
29 |
30 | # camera inforamation
31 | q_cams = np.load('./stamp/q_cams.npy')
32 | g_cams = np.load('./stamp/gallery_camera_inf.npy')
33 |
34 | # distance matrix
35 | qf = np.load('./data/qf_new.npy')
36 | gf = np.load('./data/gf_multi.npy')
37 | distori = np.dot(qf, np.transpose(gf))
38 | distori = 2. - 2 * distori # change the cosine similarity metric to euclidean similarity metric
39 |
40 | distmat = copy.deepcopy(distori)
41 |
42 | distance1 = np.zeros(36)
43 | distance1[27-1] = 0
44 | distance1[28-1] = 28
45 | distance1[29-1] = 46
46 | distance1[33-1] = 60
47 | distance1[34-1] = 76
48 | distance1[35-1] = 84
49 | distance1[36-1] = 90
50 |
51 | distance2 = np.zeros(36)
52 | distance2[27-1] = 94
53 | distance2[28-1] = 42
54 | distance2[29-1] = 36
55 | distance2[33-1] = 25
56 | distance2[34-1] = 21
57 | distance2[35-1] = 13
58 | distance2[36-1] = 0
59 |
60 | framegaps = np.ones([36,36])*400
61 | framegaps[26,:]= 460
62 | framegaps[27,:]= 180
63 | framegaps[28,:]= 240
64 | framegaps[32,:]= 270
65 | framegaps[33,:]= 170
66 | framegaps[34,:]= 130
67 | framegaps[35,:]= 120
68 |
69 | orisQuery = np.load('./stamp/orisQuery.npy')
70 | orisGallery = np.load('./stamp/orisGallery.npy')
71 |
72 | def func_stamps(distmat, q_camids, g_camids, frameQuery, frameGallery, framegaps,
73 | distance1, distance2, orisQuerys, orisGallerys, max_rank=100):
74 |
75 | num_q, num_g = distmat.shape
76 | newdist = np.zeros([num_q, num_g])
77 | if num_g < max_rank:
78 | max_rank = num_g
79 | print("Note: number of gallery samples is quite small, got {}".format(num_g))
80 | indices = np.argsort(distmat, axis=1)
81 |
82 | for q_idx in range(num_q):
83 | q_camid = q_camids[q_idx]
84 | q_frame = frameQuery[q_idx]
85 | oriQuery = orisQuerys[int(q_idx)]
86 | # remove gallery samples that have the same pid and camid with query
87 | order = indices[q_idx]
88 | remove = g_camids[order] == q_camid
89 |
90 | if q_camid < 10 :
91 | if q_camid == 6:
92 | remove = remove | ((abs(frameGallery[order] - q_frame) > 60) & (g_camids[order] == 9))
93 | elif q_camid == 9:
94 | remove = remove | ((abs(frameGallery[order] - q_frame) > 50) & (g_camids[order] == 6))
95 | else:
96 | cameras = [27, 28, 29, 33, 34, 35, 36]
97 | distQG = q_frame - frameGallery[order]
98 | for camera in cameras:
99 | if camera == q_camid:
100 | continue
101 | cameraGallery = camera
102 | if oriQuery == 0:
103 | center = (distance1[q_camid - 1] - distance1[cameraGallery - 1]) * 10
104 | else:
105 | center = (distance2[q_camid - 1] - distance2[cameraGallery - 1]) * 10
106 | remove = remove | ((abs(distQG - center) > framegaps[q_camid - 1, cameraGallery - 1]) & (
107 | g_camids[order] == cameraGallery))
108 | if oriQuery == 0:
109 | remove = remove | (orisGallery == 1.0)
110 | else:
111 | remove = remove | (orisGallery == 0.0)
112 | # filter retrieve results
113 | keep = np.invert(remove)
114 | newdist[q_idx, :np.sum(keep)] = distmat[q_idx][keep]
115 | distmat[q_idx][remove] = 2 # set distance to max number
116 |
117 | return distmat
118 |
119 | # fliter retrieve results by using location and time stamps
120 | dist = func_stamps(distmat, q_cams, g_cams, frameQuery, frameGallery, framegaps,
121 | distance1, distance2, orisQuery, orisGallery)
122 |
123 | # location information
124 | g_index_s05 = np.load('./stamp/g_index_s05.npy')
125 | q_index_s05 = np.load('./stamp/q_index_s05.npy')
126 |
127 | q_index = np.load('./stamp/q_index_s02.npy')
128 | g_index = np.load('./stamp/g_index_s02.npy')
129 |
130 | # scene filter for S02
131 | g_indice_scene = g_index_s05 #S05 indice
132 | for i in range(len(q_index)):
133 | key = q_index[i]
134 | dist[key][g_indice_scene] = 2
135 |
136 | # scene filter for S05
137 | g_indice_scene = g_index #S02 indice
138 | s05_indice = q_index_s05
139 | for i in range(len(s05_indice)):
140 | key = s05_indice[i]
141 | dist[key][g_indice_scene] = 2
142 | # save results
143 | np.save('./results/distmat_after.npy', dist)
144 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/config/__init__.py:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | """
3 | @author: sherlock
4 | @contact: sherlockliao01@gmail.com
5 | """
6 |
7 | from .defaults import _C as cfg
8 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/config/defaults.py:
--------------------------------------------------------------------------------
1 | from yacs.config import CfgNode as CN
2 |
3 | # -----------------------------------------------------------------------------
4 | # Convention about Training / Test specific parameters
5 | # -----------------------------------------------------------------------------
6 | # Whenever an argument can be either used for training or for testing, the
7 | # corresponding name will be post-fixed by a _TRAIN for a training parameter,
8 | # or _TEST for a test-specific parameter.
9 | # For example, the number of images during training will be
10 | # IMAGES_PER_BATCH_TRAIN, while the number of images for testing will be
11 | # IMAGES_PER_BATCH_TEST
12 |
13 | # -----------------------------------------------------------------------------
14 | # Config definition
15 | # -----------------------------------------------------------------------------
16 |
17 | _C = CN()
18 |
19 | _C.MODEL = CN()
20 | _C.MODEL.DEVICE = "cuda"
21 | _C.MODEL.NAME = 'densenet121'
22 | _C.MODEL.LAST_STRIDE = 1
23 | _C.MODEL.PRETRAIN_PATH = ''
24 | # -----------------------------------------------------------------------------
25 | # INPUT
26 | # -----------------------------------------------------------------------------
27 | _C.INPUT = CN()
28 | # Size of the image during training
29 | _C.INPUT.SIZE_TRAIN = [384, 128]
30 | # Size of the image during test
31 | _C.INPUT.SIZE_TEST = [384, 128]
32 | # Random probability for image horizontal flip
33 | _C.INPUT.PROB = 0.5
34 | # Values to be used for image normalization
35 | _C.INPUT.PIXEL_MEAN = [0.485, 0.456, 0.406]
36 | # Values to be used for image normalization
37 | _C.INPUT.PIXEL_STD = [0.229, 0.224, 0.225]
38 | # Value of padding size
39 | _C.INPUT.PADDING = 10
40 | # COLORJITTER
41 | _C.INPUT.COLORJITTER = False
42 |
43 | # -----------------------------------------------------------------------------
44 | # Dataset
45 | # -----------------------------------------------------------------------------
46 | _C.DATASETS = CN()
47 | # List of the dataset names for training, as present in paths_catalog.py
48 | _C.DATASETS.NAMES = ('market1501')
49 |
50 | # -----------------------------------------------------------------------------
51 | # DataLoader
52 | # -----------------------------------------------------------------------------
53 | _C.DATALOADER = CN()
54 | # Number of data loading threads
55 | _C.DATALOADER.NUM_WORKERS = 8
56 | # Sampler for data loading
57 | _C.DATALOADER.SAMPLER = 'softmax'
58 | # Number of instance for one batch
59 | _C.DATALOADER.NUM_INSTANCE = 16
60 | # SOFT_MARGIN
61 | _C.DATALOADER.SOFT_MARGIN = False
62 |
63 | # ---------------------------------------------------------------------------- #
64 | # Solver
65 | # ---------------------------------------------------------------------------- #
66 | _C.SOLVER = CN()
67 | _C.SOLVER.OPTIMIZER_NAME = "Adam"
68 |
69 | _C.SOLVER.MAX_EPOCHS = 50
70 |
71 | _C.SOLVER.BASE_LR = 3e-4
72 | _C.SOLVER.BIAS_LR_FACTOR = 2
73 |
74 | _C.SOLVER.MOMENTUM = 0.9
75 |
76 | _C.SOLVER.MARGIN = 0.3 # None for soft margin or 0.3
77 |
78 | _C.SOLVER.WEIGHT_DECAY = 0.0005
79 | _C.SOLVER.WEIGHT_DECAY_BIAS = 0.
80 |
81 | _C.SOLVER.GAMMA = 0.1
82 | _C.SOLVER.STEPS = (30, 55)
83 |
84 | _C.SOLVER.WARMUP_FACTOR = 1.0 / 3
85 | _C.SOLVER.WARMUP_ITERS = 500
86 | _C.SOLVER.WARMUP_METHOD = "linear"
87 |
88 | _C.SOLVER.CHECKPOINT_PERIOD = 50
89 | _C.SOLVER.LOG_PERIOD = 100
90 | _C.SOLVER.EVAL_PERIOD = 50
91 | # Number of images per batch
92 | # This is global, so if we have 8 GPUs and IMS_PER_BATCH = 16, each GPU will
93 | # see 2 images per batch
94 | _C.SOLVER.IMS_PER_BATCH = 64
95 |
96 | # This is global, so if we have 8 GPUs and IMS_PER_BATCH = 16, each GPU will
97 | # see 2 images per batch
98 | _C.TEST = CN()
99 | _C.TEST.IMS_PER_BATCH = 128
100 | _C.TEST.WEIGHT = ""
101 | _C.TEST.QF_NAME = ""
102 | _C.TEST.GF_NAME = ""
103 | # ---------------------------------------------------------------------------- #
104 | # Misc options
105 | # ---------------------------------------------------------------------------- #
106 | _C.OUTPUT_DIR = ""
107 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/configs/softmax_triplet_VR.yml:
--------------------------------------------------------------------------------
1 | MODEL:
2 | PRETRAIN_PATH: './modeling/densenet121-fbdb23505.pth'
3 |
4 |
5 | INPUT:
6 | SIZE_TRAIN: [288, 288]
7 | SIZE_TEST: [256, 256]
8 | PROB: 0.5 # random horizontal flip
9 | PADDING: 10
10 | COLORJITTER: False # for model ensemble
11 |
12 | DATASETS:
13 | NAMES: ('VR')
14 |
15 | DATALOADER:
16 | SAMPLER: 'softmax_triplet'
17 | NUM_INSTANCE: 4
18 | NUM_WORKERS: 2
19 | SOFT_MARGIN: False # for model ensemble
20 |
21 | SOLVER:
22 | OPTIMIZER_NAME: 'SGD'
23 | MAX_EPOCHS: 120
24 | BASE_LR: 0.01 #0.00035
25 | BIAS_LR_FACTOR: 1
26 | WEIGHT_DECAY: 0.0005
27 | WEIGHT_DECAY_BIAS: 0.0005
28 | IMS_PER_BATCH: 64
29 |
30 | STEPS: [30, 60, 100]
31 | GAMMA: 0.1
32 |
33 | WARMUP_FACTOR: 0.01
34 | WARMUP_ITERS: 10
35 | WARMUP_METHOD: 'linear'
36 |
37 | CHECKPOINT_PERIOD: 20
38 | LOG_PERIOD: 120
39 | EVAL_PERIOD: 20
40 |
41 | TEST:
42 | IMS_PER_BATCH: 256
43 | WEIGHT: "path"
44 |
45 | OUTPUT_DIR: "./CHECKPOINTS/VR/softmax_triplet_LSR_VR"
46 |
47 |
48 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/configs/softmax_triplet_VR_test.yml:
--------------------------------------------------------------------------------
1 | MODEL:
2 | PRETRAIN_PATH: './modeling/densenet121-fbdb23505.pth'
3 |
4 |
5 | INPUT:
6 | SIZE_TRAIN: [288, 288]
7 | SIZE_TEST: [256, 256]
8 | PROB: 0.5 # random horizontal flip
9 | PADDING: 10
10 | COLORJITTER: False # for model ensemble
11 |
12 | DATASETS:
13 | NAMES: ('VR_test')
14 |
15 | DATALOADER:
16 | SAMPLER: 'softmax_triplet'
17 | NUM_INSTANCE: 4
18 | NUM_WORKERS: 2
19 | SOFT_MARGIN: False # for model ensemble
20 |
21 | SOLVER:
22 | OPTIMIZER_NAME: 'SGD'
23 | MAX_EPOCHS: 120
24 | BASE_LR: 0.01 #0.00035
25 | BIAS_LR_FACTOR: 1
26 | WEIGHT_DECAY: 0.0005
27 | WEIGHT_DECAY_BIAS: 0.0005
28 | IMS_PER_BATCH: 64
29 |
30 | STEPS: [30, 60, 100]
31 | GAMMA: 0.1
32 |
33 | WARMUP_FACTOR: 0.01
34 | WARMUP_ITERS: 10
35 | WARMUP_METHOD: 'linear'
36 |
37 | CHECKPOINT_PERIOD: 20
38 | LOG_PERIOD: 120
39 | EVAL_PERIOD: 20
40 |
41 | TEST:
42 | IMS_PER_BATCH: 256
43 | WEIGHT: "path"
44 | QF_NAME: "qf_ori"
45 | GF_NAME: "gf_ori"
46 |
47 | OUTPUT_DIR: "./CHECKPOINTS/VR/softmax_triplet_LSR_VeRi_test"
48 |
49 |
50 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/configs/softmax_triplet_VeRi.yml:
--------------------------------------------------------------------------------
1 | MODEL:
2 | PRETRAIN_PATH: './modeling/densenet121-fbdb23505.pth'
3 |
4 |
5 | INPUT:
6 | SIZE_TRAIN: [288, 288]
7 | SIZE_TEST: [256, 256]
8 | PROB: 0.5 # random horizontal flip
9 | PADDING: 10
10 | COLORJITTER: False # for model ensemble
11 |
12 | DATASETS:
13 | NAMES: ('VeRi')
14 |
15 | DATALOADER:
16 | SAMPLER: 'softmax_triplet'
17 | NUM_INSTANCE: 4
18 | NUM_WORKERS: 2
19 | SOFT_MARGIN: False # for model ensemble
20 |
21 | SOLVER:
22 | OPTIMIZER_NAME: 'SGD'
23 | MAX_EPOCHS: 120
24 | BASE_LR: 0.01 #0.00035
25 | BIAS_LR_FACTOR: 1
26 | WEIGHT_DECAY: 0.0005
27 | WEIGHT_DECAY_BIAS: 0.0005
28 | IMS_PER_BATCH: 64
29 |
30 | STEPS: [30, 60, 100]
31 | GAMMA: 0.1
32 |
33 | WARMUP_FACTOR: 0.01
34 | WARMUP_ITERS: 10
35 | WARMUP_METHOD: 'linear'
36 |
37 | CHECKPOINT_PERIOD: 20
38 | LOG_PERIOD: 120
39 | EVAL_PERIOD: 20
40 |
41 | TEST:
42 | IMS_PER_BATCH: 256
43 | WEIGHT: "path"
44 |
45 | OUTPUT_DIR: "./CHECKPOINTS/VeRi/softmax_triplet_LSR_VeRi"
46 |
47 |
48 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/data/__init__.py:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | """
3 | @author: sherlock
4 | @contact: sherlockliao01@gmail.com
5 | """
6 |
7 | from .build import make_data_loader
8 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/data/build.py:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | """
3 | @author: liaoxingyu
4 | @contact: sherlockliao01@gmail.com
5 | """
6 |
7 | from torch.utils.data import DataLoader
8 |
9 | from .collate_batch import train_collate_fn, val_collate_fn
10 | from .datasets import init_dataset, ImageDataset
11 | from .samplers import RandomIdentitySampler
12 | from .transforms import build_transforms
13 |
14 |
15 | def make_data_loader(cfg):
16 | train_transforms = build_transforms(cfg, is_train=True)
17 | val_transforms = build_transforms(cfg, is_train=False)
18 | num_workers = cfg.DATALOADER.NUM_WORKERS
19 | if len(cfg.DATASETS.NAMES) == 1:
20 | dataset = init_dataset(cfg.DATASETS.NAMES)
21 | else:
22 | # TODO: add multi dataset to train
23 | dataset = init_dataset(cfg.DATASETS.NAMES)
24 |
25 | num_classes = dataset.num_train_pids
26 | train_set = ImageDataset(dataset.train, train_transforms)
27 | if cfg.DATALOADER.SAMPLER == 'softmax':
28 | train_loader = DataLoader(
29 | train_set, batch_size=cfg.SOLVER.IMS_PER_BATCH, shuffle=True, num_workers=num_workers,
30 | collate_fn=train_collate_fn
31 | )
32 | else:
33 | train_loader = DataLoader(
34 | train_set, batch_size=cfg.SOLVER.IMS_PER_BATCH,
35 | sampler=RandomIdentitySampler(dataset.train, cfg.SOLVER.IMS_PER_BATCH, cfg.DATALOADER.NUM_INSTANCE),
36 | num_workers=num_workers, collate_fn=train_collate_fn
37 | )
38 |
39 | val_set = ImageDataset(dataset.query + dataset.gallery, val_transforms)
40 | val_loader = DataLoader(
41 | val_set, batch_size=cfg.TEST.IMS_PER_BATCH, shuffle=False, num_workers=num_workers,
42 | collate_fn=val_collate_fn
43 | )
44 | return train_loader, val_loader, len(dataset.query), num_classes
45 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/data/collate_batch.py:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | """
3 | @author: liaoxingyu
4 | @contact: sherlockliao01@gmail.com
5 | """
6 |
7 | import torch
8 |
9 |
10 | def train_collate_fn(batch):
11 | imgs, pids, _, _, = zip(*batch)
12 | pids = torch.tensor(pids, dtype=torch.int64)
13 | return torch.stack(imgs, dim=0), pids
14 |
15 |
16 | def val_collate_fn(batch):
17 | imgs, pids, camids, im_path = zip(*batch)
18 | return torch.stack(imgs, dim=0), pids, camids
19 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/data/datasets/VR.py:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | """
3 | @author: weijian
4 | @contact: dengwj16@gmail.com
5 | """
6 |
7 | import glob
8 | import re
9 | import xml.dom.minidom as XD
10 | import os.path as osp
11 |
12 | from .bases import BaseImageDataset
13 |
14 |
15 | class VR(BaseImageDataset):
16 | """
17 | VR
18 |
19 | Dataset statistics:
20 |
21 | """
22 | dataset_dir = 'VR'
23 | dataset_dir_test = './data/VeRi'
24 |
25 | def __init__(self, root='./data', verbose=True, **kwargs):
26 | super(VR, self).__init__()
27 | self.dataset_dir = osp.join(root, self.dataset_dir)
28 | self.train_dir = osp.join(self.dataset_dir, 'image_train/')
29 | self.query_dir = osp.join(self.dataset_dir_test, 'image_query/')
30 | self.gallery_dir = osp.join(self.dataset_dir_test, 'image_test/')
31 |
32 | self._check_before_run()
33 |
34 | train = self._process_dir(self.train_dir, relabel=True)
35 | query = self._process_dir_test(self.query_dir, relabel=False)
36 | gallery = self._process_dir_test(self.gallery_dir, relabel=False)
37 |
38 | if verbose:
39 | print("=> VR loaded")
40 | self.print_dataset_statistics(train, query, gallery)
41 |
42 | self.train = train
43 | self.query = query
44 | self.gallery = gallery
45 |
46 | self.num_train_pids, self.num_train_imgs, self.num_train_cams = self.get_imagedata_info(self.train)
47 | self.num_query_pids, self.num_query_imgs, self.num_query_cams = self.get_imagedata_info(self.query)
48 | self.num_gallery_pids, self.num_gallery_imgs, self.num_gallery_cams = self.get_imagedata_info(self.gallery)
49 |
50 | def _check_before_run(self):
51 | """Check if all files are available before going deeper"""
52 | if not osp.exists(self.dataset_dir):
53 | raise RuntimeError("'{}' is not available".format(self.dataset_dir))
54 | if not osp.exists(self.train_dir):
55 | raise RuntimeError("'{}' is not available".format(self.train_dir))
56 | if not osp.exists(self.query_dir):
57 | raise RuntimeError("'{}' is not available".format(self.query_dir))
58 | if not osp.exists(self.gallery_dir):
59 | raise RuntimeError("'{}' is not available".format(self.gallery_dir))
60 |
61 | def _process_dir(self, dir_path, relabel=False):
62 | xml_dir =osp.join('./data/VR', 'train_label.xml')
63 | info = XD.parse(xml_dir).documentElement.getElementsByTagName('Item')
64 |
65 | pid_container = set()
66 | for element in range(len(info)):
67 | pid = int(info[element].getAttribute('vehicleID'))
68 | if pid == -1: continue # junk images are just ignored
69 | pid_container.add(pid)
70 | pid2label = {pid: label for label, pid in enumerate(pid_container)}
71 |
72 | dataset = []
73 | for element in range(len(info)):
74 | pid, camid = map(int, [info[element].getAttribute('vehicleID'), info[element].getAttribute('cameraID')[1:]])
75 | image_name = str(info[element].getAttribute('imageName'))
76 | if pid == -1: continue # junk images are just ignored
77 | if relabel: pid = pid2label[pid]
78 | dataset.append((osp.join(dir_path, image_name), pid, camid))
79 |
80 | return dataset
81 |
82 | def _process_dir_test(self, dir_path, relabel=False):
83 | img_paths = glob.glob(osp.join(dir_path, '*.jpg'))
84 | pattern = re.compile(r'([-\d]+)_c(\d\d\d)')
85 | pid_container = set()
86 | for img_path in img_paths:
87 | pid, _ = map(int, pattern.search(img_path).groups())
88 | if pid == -1: continue # junk images are just ignored
89 | pid_container.add(pid)
90 | pid2label = {pid: label for label, pid in enumerate(pid_container)}
91 |
92 | dataset = []
93 | for img_path in img_paths:
94 | pid, camid = map(int, pattern.search(img_path).groups())
95 | if pid == -1: continue # junk images are just ignored
96 | camid -= 1 # index starts from 0
97 | if relabel: pid = pid2label[pid]
98 | dataset.append((img_path, pid, camid))
99 |
100 | return dataset
101 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/data/datasets/VR_test.py:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | """
3 | @author: weijian
4 | @contact: dengwj16@gmail.com
5 | """
6 |
7 | import glob
8 | import re
9 | import xml.dom.minidom as XD
10 | import os.path as osp
11 |
12 | from .bases import BaseImageDataset
13 |
14 |
15 | class VR_test(BaseImageDataset):
16 | """
17 | VR_test
18 |
19 | Dataset statistics:
20 |
21 | """
22 | dataset_dir = 'VR'
23 | dataset_dir_test = './data/VR'
24 |
25 | def __init__(self, root='./data', verbose=True, **kwargs):
26 | super(VR_test, self).__init__()
27 | self.dataset_dir = osp.join(root, self.dataset_dir)
28 | self.train_dir = osp.join(self.dataset_dir, 'image_train/')
29 | self.query_dir = osp.join(self.dataset_dir_test, 'image_query/')
30 | self.gallery_dir = osp.join(self.dataset_dir_test, 'image_test/')
31 |
32 | self._check_before_run()
33 |
34 | train = self._process_dir(self.train_dir, relabel=True)
35 | query = self._process_dir_demo(self.query_dir, relabel=False)
36 | gallery = self._process_dir_demo(self.gallery_dir, relabel=False)
37 | if verbose:
38 | print("=> VR loaded")
39 | self.print_dataset_statistics(train, query, gallery)
40 |
41 | self.train = train
42 | self.query = query
43 | self.gallery = gallery
44 |
45 | self.num_train_pids, self.num_train_imgs, self.num_train_cams = self.get_imagedata_info(self.train)
46 | self.num_query_pids, self.num_query_imgs, self.num_query_cams = self.get_imagedata_info(self.query)
47 | self.num_gallery_pids, self.num_gallery_imgs, self.num_gallery_cams = self.get_imagedata_info(self.gallery)
48 |
49 | def _check_before_run(self):
50 | """Check if all files are available before going deeper"""
51 | if not osp.exists(self.dataset_dir):
52 | raise RuntimeError("'{}' is not available".format(self.dataset_dir))
53 | if not osp.exists(self.train_dir):
54 | raise RuntimeError("'{}' is not available".format(self.train_dir))
55 | if not osp.exists(self.query_dir):
56 | raise RuntimeError("'{}' is not available".format(self.query_dir))
57 | if not osp.exists(self.gallery_dir):
58 | raise RuntimeError("'{}' is not available".format(self.gallery_dir))
59 |
60 | def _process_dir(self, dir_path, relabel=False):
61 | xml_dir =osp.join('./data/VR', 'train_label.xml')
62 | info = XD.parse(xml_dir).documentElement.getElementsByTagName('Item')
63 |
64 | pid_container = set()
65 | for element in range(len(info)):
66 | pid = int(info[element].getAttribute('vehicleID'))
67 | if pid == -1: continue # junk images are just ignored
68 | pid_container.add(pid)
69 | pid2label = {pid: label for label, pid in enumerate(pid_container)}
70 |
71 | dataset = []
72 | for element in range(len(info)):
73 | pid, camid = map(int, [info[element].getAttribute('vehicleID'), info[element].getAttribute('cameraID')[1:]])
74 | image_name = str(info[element].getAttribute('imageName'))
75 | camid -= 1 # index starts from 0
76 | if relabel: pid = pid2label[pid]
77 | dataset.append((osp.join(dir_path, image_name), pid, camid))
78 |
79 | return dataset
80 |
81 |
82 | def _process_dir_demo(self, dir_path, relabel=False):
83 | img_paths = glob.glob(osp.join(dir_path, '*.jpg'))
84 | img_paths.sort()
85 | pid_container = set()
86 | for img_path in img_paths:
87 | pid = 1
88 | if pid == -1: continue # junk images are just ignored
89 | pid_container.add(pid)
90 | pid2label = {pid: label for label, pid in enumerate(pid_container)}
91 |
92 | dataset = []
93 | for img_path in img_paths:
94 | pid, camid = 1, 2
95 | if pid == -1: continue # junk images are just ignored
96 | camid -= 1 # index starts from 0
97 | if relabel: pid = pid2label[pid]
98 | dataset.append((img_path, pid, camid))
99 |
100 | return dataset
101 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/data/datasets/VeRi.py:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | """
3 | @author: weijian
4 | @contact: dengwj16@gmail.com
5 | """
6 |
7 | import glob
8 | import re
9 | import xml.dom.minidom as XD
10 | import os.path as osp
11 |
12 | from .bases import BaseImageDataset
13 |
14 |
15 | class VeRi(BaseImageDataset):
16 | """
17 |
18 | VeRi
19 |
20 | """
21 | dataset_dir = 'VeRi'
22 | dataset_dir_test = './data/VeRi'
23 |
24 | def __init__(self, root='./data', verbose=True, **kwargs):
25 | super(VeRi, self).__init__()
26 | self.dataset_dir = osp.join(root, self.dataset_dir)
27 | self.train_dir = osp.join(self.dataset_dir, 'image_train/')
28 | self.query_dir = osp.join(self.dataset_dir, 'image_query/')
29 | self.gallery_dir = osp.join(self.dataset_dir, 'image_test/')
30 |
31 | self._check_before_run()
32 |
33 | train = self._process_dir_test(self.train_dir, relabel=True)
34 | query = self._process_dir_test(self.query_dir, relabel=False)
35 | gallery = self._process_dir_test(self.gallery_dir, relabel=False)
36 |
37 | if verbose:
38 | print("=> VR loaded")
39 | self.print_dataset_statistics(train, query, gallery)
40 |
41 | self.train = train
42 | self.query = query
43 | self.gallery = gallery
44 |
45 | self.num_train_pids, self.num_train_imgs, self.num_train_cams = self.get_imagedata_info(self.train)
46 | self.num_query_pids, self.num_query_imgs, self.num_query_cams = self.get_imagedata_info(self.query)
47 | self.num_gallery_pids, self.num_gallery_imgs, self.num_gallery_cams = self.get_imagedata_info(self.gallery)
48 |
49 | def _check_before_run(self):
50 | """Check if all files are available before going deeper"""
51 | if not osp.exists(self.dataset_dir):
52 | raise RuntimeError("'{}' is not available".format(self.dataset_dir))
53 | if not osp.exists(self.train_dir):
54 | raise RuntimeError("'{}' is not available".format(self.train_dir))
55 | if not osp.exists(self.query_dir):
56 | raise RuntimeError("'{}' is not available".format(self.query_dir))
57 | if not osp.exists(self.gallery_dir):
58 | raise RuntimeError("'{}' is not available".format(self.gallery_dir))
59 |
60 |
61 | def _process_dir_test(self, dir_path, relabel=False):
62 | img_paths = glob.glob(osp.join(dir_path, '*.jpg'))
63 | pattern = re.compile(r'([-\d]+)_c(\d\d\d)')
64 | pid_container = set()
65 | for img_path in img_paths:
66 | pid, _ = map(int, pattern.search(img_path).groups())
67 | if pid == -1: continue # junk images are just ignored
68 | pid_container.add(pid)
69 | pid2label = {pid: label for label, pid in enumerate(pid_container)}
70 |
71 | dataset = []
72 | for img_path in img_paths:
73 | pid, camid = map(int, pattern.search(img_path).groups())
74 | if pid == -1: continue # junk images are just ignored
75 | camid -= 1 # index starts from 0
76 | if relabel: pid = pid2label[pid]
77 | dataset.append((img_path, pid, camid))
78 |
79 | return dataset
80 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/data/datasets/__init__.py:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | """
3 | @author: liaoxingyu
4 | @contact: sherlockliao01@gmail.com
5 | """
6 | from .cuhk03 import CUHK03
7 | from .dukemtmcreid import DukeMTMCreID
8 | from .market1501 import Market1501
9 | from .VR import VR
10 | from .VR_test import VR_test
11 | from .VeRi import VeRi
12 | from .dataset_loader import ImageDataset
13 |
14 | __factory = {
15 | 'market1501': Market1501,
16 | 'cuhk03': CUHK03,
17 | 'dukemtmc': DukeMTMCreID,
18 | 'VR': VR,
19 | 'VR_test': VR_test,
20 | 'VeRi': VeRi,
21 | }
22 |
23 |
24 | def get_names():
25 | return __factory.keys()
26 |
27 |
28 | def init_dataset(name, *args, **kwargs):
29 | if name not in __factory.keys():
30 | raise KeyError("Unknown datasets: {}".format(name))
31 | return __factory[name](*args, **kwargs)
32 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/data/datasets/bases.py:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | """
3 | @author: sherlock
4 | @contact: sherlockliao01@gmail.com
5 | """
6 |
7 | import numpy as np
8 |
9 |
10 | class BaseDataset(object):
11 | """
12 | Base class of reid dataset
13 | """
14 |
15 | def get_imagedata_info(self, data):
16 | pids, cams = [], []
17 | for _, pid, camid in data:
18 | pids += [pid]
19 | cams += [camid]
20 | pids = set(pids)
21 | cams = set(cams)
22 | num_pids = len(pids)
23 | num_cams = len(cams)
24 | num_imgs = len(data)
25 | return num_pids, num_imgs, num_cams
26 |
27 | def get_videodata_info(self, data, return_tracklet_stats=False):
28 | pids, cams, tracklet_stats = [], [], []
29 | for img_paths, pid, camid in data:
30 | pids += [pid]
31 | cams += [camid]
32 | tracklet_stats += [len(img_paths)]
33 | pids = set(pids)
34 | cams = set(cams)
35 | num_pids = len(pids)
36 | num_cams = len(cams)
37 | num_tracklets = len(data)
38 | if return_tracklet_stats:
39 | return num_pids, num_tracklets, num_cams, tracklet_stats
40 | return num_pids, num_tracklets, num_cams
41 |
42 | def print_dataset_statistics(self):
43 | raise NotImplementedError
44 |
45 |
46 | class BaseImageDataset(BaseDataset):
47 | """
48 | Base class of image reid dataset
49 | """
50 |
51 | def print_dataset_statistics(self, train, query, gallery):
52 | num_train_pids, num_train_imgs, num_train_cams = self.get_imagedata_info(train)
53 | num_query_pids, num_query_imgs, num_query_cams = self.get_imagedata_info(query)
54 | num_gallery_pids, num_gallery_imgs, num_gallery_cams = self.get_imagedata_info(gallery)
55 |
56 | print("Dataset statistics:")
57 | print(" ----------------------------------------")
58 | print(" subset | # ids | # images | # cameras")
59 | print(" ----------------------------------------")
60 | print(" train | {:5d} | {:8d} | {:9d}".format(num_train_pids, num_train_imgs, num_train_cams))
61 | print(" query | {:5d} | {:8d} | {:9d}".format(num_query_pids, num_query_imgs, num_query_cams))
62 | print(" gallery | {:5d} | {:8d} | {:9d}".format(num_gallery_pids, num_gallery_imgs, num_gallery_cams))
63 | print(" ----------------------------------------")
64 |
65 |
66 | class BaseVideoDataset(BaseDataset):
67 | """
68 | Base class of video reid dataset
69 | """
70 |
71 | def print_dataset_statistics(self, train, query, gallery):
72 | num_train_pids, num_train_tracklets, num_train_cams, train_tracklet_stats = \
73 | self.get_videodata_info(train, return_tracklet_stats=True)
74 |
75 | num_query_pids, num_query_tracklets, num_query_cams, query_tracklet_stats = \
76 | self.get_videodata_info(query, return_tracklet_stats=True)
77 |
78 | num_gallery_pids, num_gallery_tracklets, num_gallery_cams, gallery_tracklet_stats = \
79 | self.get_videodata_info(gallery, return_tracklet_stats=True)
80 |
81 | tracklet_stats = train_tracklet_stats + query_tracklet_stats + gallery_tracklet_stats
82 | min_num = np.min(tracklet_stats)
83 | max_num = np.max(tracklet_stats)
84 | avg_num = np.mean(tracklet_stats)
85 |
86 | print("Dataset statistics:")
87 | print(" -------------------------------------------")
88 | print(" subset | # ids | # tracklets | # cameras")
89 | print(" -------------------------------------------")
90 | print(" train | {:5d} | {:11d} | {:9d}".format(num_train_pids, num_train_tracklets, num_train_cams))
91 | print(" query | {:5d} | {:11d} | {:9d}".format(num_query_pids, num_query_tracklets, num_query_cams))
92 | print(" gallery | {:5d} | {:11d} | {:9d}".format(num_gallery_pids, num_gallery_tracklets, num_gallery_cams))
93 | print(" -------------------------------------------")
94 | print(" number of images per tracklet: {} ~ {}, average {:.2f}".format(min_num, max_num, avg_num))
95 | print(" -------------------------------------------")
96 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/data/datasets/cuhk03.py:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | """
3 | @author: liaoxingyu
4 | @contact: liaoxingyu2@jd.com
5 | """
6 |
7 | import h5py
8 | import os.path as osp
9 | from scipy.io import loadmat
10 | from scipy.misc import imsave
11 |
12 | from utils.iotools import mkdir_if_missing, write_json, read_json
13 | from .bases import BaseImageDataset
14 |
15 |
16 | class CUHK03(BaseImageDataset):
17 | """
18 | CUHK03
19 | Reference:
20 | Li et al. DeepReID: Deep Filter Pairing Neural Network for Person Re-identification. CVPR 2014.
21 | URL: http://www.ee.cuhk.edu.hk/~xgwang/CUHK_identification.html#!
22 |
23 | Dataset statistics:
24 | # identities: 1360
25 | # images: 13164
26 | # cameras: 6
27 | # splits: 20 (classic)
28 | Args:
29 | split_id (int): split index (default: 0)
30 | cuhk03_labeled (bool): whether to load labeled images; if false, detected images are loaded (default: False)
31 | """
32 | dataset_dir = 'cuhk03'
33 |
34 | def __init__(self, root='/export/home/lxy/DATA/reid', split_id=0, cuhk03_labeled=False,
35 | cuhk03_classic_split=False, verbose=True,
36 | **kwargs):
37 | super(CUHK03, self).__init__()
38 | self.dataset_dir = osp.join(root, self.dataset_dir)
39 | self.data_dir = osp.join(self.dataset_dir, 'cuhk03_release')
40 | self.raw_mat_path = osp.join(self.data_dir, 'cuhk-03.mat')
41 |
42 | self.imgs_detected_dir = osp.join(self.dataset_dir, 'images_detected')
43 | self.imgs_labeled_dir = osp.join(self.dataset_dir, 'images_labeled')
44 |
45 | self.split_classic_det_json_path = osp.join(self.dataset_dir, 'splits_classic_detected.json')
46 | self.split_classic_lab_json_path = osp.join(self.dataset_dir, 'splits_classic_labeled.json')
47 |
48 | self.split_new_det_json_path = osp.join(self.dataset_dir, 'splits_new_detected.json')
49 | self.split_new_lab_json_path = osp.join(self.dataset_dir, 'splits_new_labeled.json')
50 |
51 | self.split_new_det_mat_path = osp.join(self.dataset_dir, 'cuhk03_new_protocol_config_detected.mat')
52 | self.split_new_lab_mat_path = osp.join(self.dataset_dir, 'cuhk03_new_protocol_config_labeled.mat')
53 |
54 | self._check_before_run()
55 | self._preprocess()
56 |
57 | if cuhk03_labeled:
58 | image_type = 'labeled'
59 | split_path = self.split_classic_lab_json_path if cuhk03_classic_split else self.split_new_lab_json_path
60 | else:
61 | image_type = 'detected'
62 | split_path = self.split_classic_det_json_path if cuhk03_classic_split else self.split_new_det_json_path
63 |
64 | splits = read_json(split_path)
65 | assert split_id < len(splits), "Condition split_id ({}) < len(splits) ({}) is false".format(split_id,
66 | len(splits))
67 | split = splits[split_id]
68 | print("Split index = {}".format(split_id))
69 |
70 | train = split['train']
71 | query = split['query']
72 | gallery = split['gallery']
73 |
74 | if verbose:
75 | print("=> CUHK03 ({}) loaded".format(image_type))
76 | self.print_dataset_statistics(train, query, gallery)
77 |
78 | self.train = train
79 | self.query = query
80 | self.gallery = gallery
81 |
82 | self.num_train_pids, self.num_train_imgs, self.num_train_cams = self.get_imagedata_info(self.train)
83 | self.num_query_pids, self.num_query_imgs, self.num_query_cams = self.get_imagedata_info(self.query)
84 | self.num_gallery_pids, self.num_gallery_imgs, self.num_gallery_cams = self.get_imagedata_info(self.gallery)
85 |
86 | def _check_before_run(self):
87 | """Check if all files are available before going deeper"""
88 | if not osp.exists(self.dataset_dir):
89 | raise RuntimeError("'{}' is not available".format(self.dataset_dir))
90 | if not osp.exists(self.data_dir):
91 | raise RuntimeError("'{}' is not available".format(self.data_dir))
92 | if not osp.exists(self.raw_mat_path):
93 | raise RuntimeError("'{}' is not available".format(self.raw_mat_path))
94 | if not osp.exists(self.split_new_det_mat_path):
95 | raise RuntimeError("'{}' is not available".format(self.split_new_det_mat_path))
96 | if not osp.exists(self.split_new_lab_mat_path):
97 | raise RuntimeError("'{}' is not available".format(self.split_new_lab_mat_path))
98 |
99 | def _preprocess(self):
100 | """
101 | This function is a bit complex and ugly, what it does is
102 | 1. Extract data from cuhk-03.mat and save as png images.
103 | 2. Create 20 classic splits. (Li et al. CVPR'14)
104 | 3. Create new split. (Zhong et al. CVPR'17)
105 | """
106 | print(
107 | "Note: if root path is changed, the previously generated json files need to be re-generated (delete them first)")
108 | if osp.exists(self.imgs_labeled_dir) and \
109 | osp.exists(self.imgs_detected_dir) and \
110 | osp.exists(self.split_classic_det_json_path) and \
111 | osp.exists(self.split_classic_lab_json_path) and \
112 | osp.exists(self.split_new_det_json_path) and \
113 | osp.exists(self.split_new_lab_json_path):
114 | return
115 |
116 | mkdir_if_missing(self.imgs_detected_dir)
117 | mkdir_if_missing(self.imgs_labeled_dir)
118 |
119 | print("Extract image data from {} and save as png".format(self.raw_mat_path))
120 | mat = h5py.File(self.raw_mat_path, 'r')
121 |
122 | def _deref(ref):
123 | return mat[ref][:].T
124 |
125 | def _process_images(img_refs, campid, pid, save_dir):
126 | img_paths = [] # Note: some persons only have images for one view
127 | for imgid, img_ref in enumerate(img_refs):
128 | img = _deref(img_ref)
129 | # skip empty cell
130 | if img.size == 0 or img.ndim < 3: continue
131 | # images are saved with the following format, index-1 (ensure uniqueness)
132 | # campid: index of camera pair (1-5)
133 | # pid: index of person in 'campid'-th camera pair
134 | # viewid: index of view, {1, 2}
135 | # imgid: index of image, (1-10)
136 | viewid = 1 if imgid < 5 else 2
137 | img_name = '{:01d}_{:03d}_{:01d}_{:02d}.png'.format(campid + 1, pid + 1, viewid, imgid + 1)
138 | img_path = osp.join(save_dir, img_name)
139 | if not osp.isfile(img_path):
140 | imsave(img_path, img)
141 | img_paths.append(img_path)
142 | return img_paths
143 |
144 | def _extract_img(name):
145 | print("Processing {} images (extract and save) ...".format(name))
146 | meta_data = []
147 | imgs_dir = self.imgs_detected_dir if name == 'detected' else self.imgs_labeled_dir
148 | for campid, camp_ref in enumerate(mat[name][0]):
149 | camp = _deref(camp_ref)
150 | num_pids = camp.shape[0]
151 | for pid in range(num_pids):
152 | img_paths = _process_images(camp[pid, :], campid, pid, imgs_dir)
153 | assert len(img_paths) > 0, "campid{}-pid{} has no images".format(campid, pid)
154 | meta_data.append((campid + 1, pid + 1, img_paths))
155 | print("- done camera pair {} with {} identities".format(campid + 1, num_pids))
156 | return meta_data
157 |
158 | meta_detected = _extract_img('detected')
159 | meta_labeled = _extract_img('labeled')
160 |
161 | def _extract_classic_split(meta_data, test_split):
162 | train, test = [], []
163 | num_train_pids, num_test_pids = 0, 0
164 | num_train_imgs, num_test_imgs = 0, 0
165 | for i, (campid, pid, img_paths) in enumerate(meta_data):
166 |
167 | if [campid, pid] in test_split:
168 | for img_path in img_paths:
169 | camid = int(osp.basename(img_path).split('_')[2]) - 1 # make it 0-based
170 | test.append((img_path, num_test_pids, camid))
171 | num_test_pids += 1
172 | num_test_imgs += len(img_paths)
173 | else:
174 | for img_path in img_paths:
175 | camid = int(osp.basename(img_path).split('_')[2]) - 1 # make it 0-based
176 | train.append((img_path, num_train_pids, camid))
177 | num_train_pids += 1
178 | num_train_imgs += len(img_paths)
179 | return train, num_train_pids, num_train_imgs, test, num_test_pids, num_test_imgs
180 |
181 | print("Creating classic splits (# = 20) ...")
182 | splits_classic_det, splits_classic_lab = [], []
183 | for split_ref in mat['testsets'][0]:
184 | test_split = _deref(split_ref).tolist()
185 |
186 | # create split for detected images
187 | train, num_train_pids, num_train_imgs, test, num_test_pids, num_test_imgs = \
188 | _extract_classic_split(meta_detected, test_split)
189 | splits_classic_det.append({
190 | 'train': train, 'query': test, 'gallery': test,
191 | 'num_train_pids': num_train_pids, 'num_train_imgs': num_train_imgs,
192 | 'num_query_pids': num_test_pids, 'num_query_imgs': num_test_imgs,
193 | 'num_gallery_pids': num_test_pids, 'num_gallery_imgs': num_test_imgs,
194 | })
195 |
196 | # create split for labeled images
197 | train, num_train_pids, num_train_imgs, test, num_test_pids, num_test_imgs = \
198 | _extract_classic_split(meta_labeled, test_split)
199 | splits_classic_lab.append({
200 | 'train': train, 'query': test, 'gallery': test,
201 | 'num_train_pids': num_train_pids, 'num_train_imgs': num_train_imgs,
202 | 'num_query_pids': num_test_pids, 'num_query_imgs': num_test_imgs,
203 | 'num_gallery_pids': num_test_pids, 'num_gallery_imgs': num_test_imgs,
204 | })
205 |
206 | write_json(splits_classic_det, self.split_classic_det_json_path)
207 | write_json(splits_classic_lab, self.split_classic_lab_json_path)
208 |
209 | def _extract_set(filelist, pids, pid2label, idxs, img_dir, relabel):
210 | tmp_set = []
211 | unique_pids = set()
212 | for idx in idxs:
213 | img_name = filelist[idx][0]
214 | camid = int(img_name.split('_')[2]) - 1 # make it 0-based
215 | pid = pids[idx]
216 | if relabel: pid = pid2label[pid]
217 | img_path = osp.join(img_dir, img_name)
218 | tmp_set.append((img_path, int(pid), camid))
219 | unique_pids.add(pid)
220 | return tmp_set, len(unique_pids), len(idxs)
221 |
222 | def _extract_new_split(split_dict, img_dir):
223 | train_idxs = split_dict['train_idx'].flatten() - 1 # index-0
224 | pids = split_dict['labels'].flatten()
225 | train_pids = set(pids[train_idxs])
226 | pid2label = {pid: label for label, pid in enumerate(train_pids)}
227 | query_idxs = split_dict['query_idx'].flatten() - 1
228 | gallery_idxs = split_dict['gallery_idx'].flatten() - 1
229 | filelist = split_dict['filelist'].flatten()
230 | train_info = _extract_set(filelist, pids, pid2label, train_idxs, img_dir, relabel=True)
231 | query_info = _extract_set(filelist, pids, pid2label, query_idxs, img_dir, relabel=False)
232 | gallery_info = _extract_set(filelist, pids, pid2label, gallery_idxs, img_dir, relabel=False)
233 | return train_info, query_info, gallery_info
234 |
235 | print("Creating new splits for detected images (767/700) ...")
236 | train_info, query_info, gallery_info = _extract_new_split(
237 | loadmat(self.split_new_det_mat_path),
238 | self.imgs_detected_dir,
239 | )
240 | splits = [{
241 | 'train': train_info[0], 'query': query_info[0], 'gallery': gallery_info[0],
242 | 'num_train_pids': train_info[1], 'num_train_imgs': train_info[2],
243 | 'num_query_pids': query_info[1], 'num_query_imgs': query_info[2],
244 | 'num_gallery_pids': gallery_info[1], 'num_gallery_imgs': gallery_info[2],
245 | }]
246 | write_json(splits, self.split_new_det_json_path)
247 |
248 | print("Creating new splits for labeled images (767/700) ...")
249 | train_info, query_info, gallery_info = _extract_new_split(
250 | loadmat(self.split_new_lab_mat_path),
251 | self.imgs_labeled_dir,
252 | )
253 | splits = [{
254 | 'train': train_info[0], 'query': query_info[0], 'gallery': gallery_info[0],
255 | 'num_train_pids': train_info[1], 'num_train_imgs': train_info[2],
256 | 'num_query_pids': query_info[1], 'num_query_imgs': query_info[2],
257 | 'num_gallery_pids': gallery_info[1], 'num_gallery_imgs': gallery_info[2],
258 | }]
259 | write_json(splits, self.split_new_lab_json_path)
260 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/data/datasets/dataset_loader.py:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | """
3 | @author: liaoxingyu
4 | @contact: sherlockliao01@gmail.com
5 | """
6 |
7 | import os.path as osp
8 | from PIL import Image
9 | from torch.utils.data import Dataset
10 |
11 |
12 | def read_image(img_path):
13 | """Keep reading image until succeed.
14 | This can avoid IOError incurred by heavy IO process."""
15 | got_img = False
16 | if not osp.exists(img_path):
17 | raise IOError("{} does not exist".format(img_path))
18 | while not got_img:
19 | try:
20 | img = Image.open(img_path).convert('RGB')
21 | got_img = True
22 | except IOError:
23 | print("IOError incurred when reading '{}'. Will redo. Don't worry. Just chill.".format(img_path))
24 | pass
25 | return img
26 |
27 |
28 | class ImageDataset(Dataset):
29 | """Image Person ReID Dataset"""
30 |
31 | def __init__(self, dataset, transform=None):
32 | self.dataset = dataset
33 | self.transform = transform
34 |
35 | def __len__(self):
36 | return len(self.dataset)
37 |
38 | def __getitem__(self, index):
39 | img_path, pid, camid = self.dataset[index]
40 | img = read_image(img_path)
41 |
42 | if self.transform is not None:
43 | img = self.transform(img)
44 |
45 | return img, pid, camid, img_path
46 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/data/datasets/dukemtmcreid.py:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | """
3 | @author: liaoxingyu
4 | @contact: liaoxingyu2@jd.com
5 | """
6 |
7 | import glob
8 | import re
9 | import urllib
10 | import zipfile
11 |
12 | import os.path as osp
13 |
14 | from utils.iotools import mkdir_if_missing
15 | from .bases import BaseImageDataset
16 |
17 |
18 | class DukeMTMCreID(BaseImageDataset):
19 | """
20 | DukeMTMC-reID
21 | Reference:
22 | 1. Ristani et al. Performance Measures and a Data Set for Multi-Target, Multi-Camera Tracking. ECCVW 2016.
23 | 2. Zheng et al. Unlabeled Samples Generated by GAN Improve the Person Re-identification Baseline in vitro. ICCV 2017.
24 | URL: https://github.com/layumi/DukeMTMC-reID_evaluation
25 |
26 | Dataset statistics:
27 | # identities: 1404 (train + query)
28 | # images:16522 (train) + 2228 (query) + 17661 (gallery)
29 | # cameras: 8
30 | """
31 | dataset_dir = 'dukemtmc-reid'
32 |
33 | def __init__(self, root='/export/home/lxy/DATA/reid', verbose=True, **kwargs):
34 | super(DukeMTMCreID, self).__init__()
35 | self.dataset_dir = osp.join(root, self.dataset_dir)
36 | self.dataset_url = 'http://vision.cs.duke.edu/DukeMTMC/data/misc/DukeMTMC-reID.zip'
37 | self.train_dir = osp.join(self.dataset_dir, 'DukeMTMC-reID/bounding_box_train')
38 | self.query_dir = osp.join(self.dataset_dir, 'DukeMTMC-reID/query')
39 | self.gallery_dir = osp.join(self.dataset_dir, 'DukeMTMC-reID/bounding_box_test')
40 |
41 | self._download_data()
42 | self._check_before_run()
43 |
44 | train = self._process_dir(self.train_dir, relabel=True)
45 | query = self._process_dir(self.query_dir, relabel=False)
46 | gallery = self._process_dir(self.gallery_dir, relabel=False)
47 |
48 | if verbose:
49 | print("=> DukeMTMC-reID loaded")
50 | self.print_dataset_statistics(train, query, gallery)
51 |
52 | self.train = train
53 | self.query = query
54 | self.gallery = gallery
55 |
56 | self.num_train_pids, self.num_train_imgs, self.num_train_cams = self.get_imagedata_info(self.train)
57 | self.num_query_pids, self.num_query_imgs, self.num_query_cams = self.get_imagedata_info(self.query)
58 | self.num_gallery_pids, self.num_gallery_imgs, self.num_gallery_cams = self.get_imagedata_info(self.gallery)
59 |
60 | def _download_data(self):
61 | if osp.exists(self.dataset_dir):
62 | print("This dataset has been downloaded.")
63 | return
64 |
65 | print("Creating directory {}".format(self.dataset_dir))
66 | mkdir_if_missing(self.dataset_dir)
67 | fpath = osp.join(self.dataset_dir, osp.basename(self.dataset_url))
68 |
69 | print("Downloading DukeMTMC-reID dataset")
70 | urllib.urlretrieve(self.dataset_url, fpath)
71 |
72 | print("Extracting files")
73 | zip_ref = zipfile.ZipFile(fpath, 'r')
74 | zip_ref.extractall(self.dataset_dir)
75 | zip_ref.close()
76 |
77 | def _check_before_run(self):
78 | """Check if all files are available before going deeper"""
79 | if not osp.exists(self.dataset_dir):
80 | raise RuntimeError("'{}' is not available".format(self.dataset_dir))
81 | if not osp.exists(self.train_dir):
82 | raise RuntimeError("'{}' is not available".format(self.train_dir))
83 | if not osp.exists(self.query_dir):
84 | raise RuntimeError("'{}' is not available".format(self.query_dir))
85 | if not osp.exists(self.gallery_dir):
86 | raise RuntimeError("'{}' is not available".format(self.gallery_dir))
87 |
88 | def _process_dir(self, dir_path, relabel=False):
89 | img_paths = glob.glob(osp.join(dir_path, '*.jpg'))
90 | pattern = re.compile(r'([-\d]+)_c(\d)')
91 |
92 | pid_container = set()
93 | for img_path in img_paths:
94 | pid, _ = map(int, pattern.search(img_path).groups())
95 | pid_container.add(pid)
96 | pid2label = {pid: label for label, pid in enumerate(pid_container)}
97 |
98 | dataset = []
99 | for img_path in img_paths:
100 | pid, camid = map(int, pattern.search(img_path).groups())
101 | assert 1 <= camid <= 8
102 | camid -= 1 # index starts from 0
103 | if relabel: pid = pid2label[pid]
104 | dataset.append((img_path, pid, camid))
105 |
106 | return dataset
107 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/data/datasets/eval_reid.py:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | """
3 | @author: liaoxingyu
4 | @contact: sherlockliao01@gmail.com
5 | """
6 |
7 | import numpy as np
8 |
9 |
10 | def eval_func(distmat, q_pids, g_pids, q_camids, g_camids, max_rank=50):
11 | """Evaluation with market1501 metric
12 | Key: for each query identity, its gallery images from the same camera view are discarded.
13 | """
14 | num_q, num_g = distmat.shape
15 | if num_g < max_rank:
16 | max_rank = num_g
17 | print("Note: number of gallery samples is quite small, got {}".format(num_g))
18 | indices = np.argsort(distmat, axis=1)
19 | matches = (g_pids[indices] == q_pids[:, np.newaxis]).astype(np.int32)
20 |
21 | # compute cmc curve for each query
22 | all_cmc = []
23 | all_AP = []
24 | num_valid_q = 0. # number of valid query
25 | for q_idx in range(num_q):
26 | # get query pid and camid
27 | q_pid = q_pids[q_idx]
28 | q_camid = q_camids[q_idx]
29 |
30 | # remove gallery samples that have the same pid and camid with query
31 | order = indices[q_idx]
32 | remove = (g_pids[order] == q_pid) & (g_camids[order] == q_camid)
33 | keep = np.invert(remove)
34 |
35 | # compute cmc curve
36 | # binary vector, positions with value 1 are correct matches
37 | orig_cmc = matches[q_idx][keep]
38 | if not np.any(orig_cmc):
39 | # this condition is true when query identity does not appear in gallery
40 | continue
41 |
42 | cmc = orig_cmc.cumsum()
43 | cmc[cmc > 1] = 1
44 |
45 | all_cmc.append(cmc[:max_rank])
46 | num_valid_q += 1.
47 |
48 | # compute average precision
49 | # reference: https://en.wikipedia.org/wiki/Evaluation_measures_(information_retrieval)#Average_precision
50 | num_rel = orig_cmc.sum()
51 | tmp_cmc = orig_cmc.cumsum()
52 | tmp_cmc = [x / (i + 1.) for i, x in enumerate(tmp_cmc)]
53 | tmp_cmc = np.asarray(tmp_cmc) * orig_cmc
54 | AP = tmp_cmc.sum() / num_rel
55 | all_AP.append(AP)
56 |
57 | assert num_valid_q > 0, "Error: all query identities do not appear in gallery"
58 |
59 | all_cmc = np.asarray(all_cmc).astype(np.float32)
60 | all_cmc = all_cmc.sum(0) / num_valid_q
61 | mAP = np.mean(all_AP)
62 |
63 | return all_cmc, mAP
64 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/data/datasets/market1501.py:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | """
3 | @author: sherlock
4 | @contact: sherlockliao01@gmail.com
5 | """
6 |
7 | import glob
8 | import re
9 |
10 | import os.path as osp
11 |
12 | from .bases import BaseImageDataset
13 |
14 |
15 | class Market1501(BaseImageDataset):
16 | """
17 | Market1501
18 | Reference:
19 | Zheng et al. Scalable Person Re-identification: A Benchmark. ICCV 2015.
20 | URL: http://www.liangzheng.org/Project/project_reid.html
21 |
22 | Dataset statistics:
23 | # identities: 1501 (+1 for background)
24 | # images: 12936 (train) + 3368 (query) + 15913 (gallery)
25 | """
26 | dataset_dir = 'market1501'
27 |
28 | def __init__(self, root='/export/home/lxy/DATA/reid', verbose=True, **kwargs):
29 | super(Market1501, self).__init__()
30 | self.dataset_dir = osp.join(root, self.dataset_dir)
31 | self.train_dir = osp.join(self.dataset_dir, 'bounding_box_train')
32 | self.query_dir = osp.join(self.dataset_dir, 'query')
33 | self.gallery_dir = osp.join(self.dataset_dir, 'bounding_box_test')
34 |
35 | self._check_before_run()
36 |
37 | train = self._process_dir(self.train_dir, relabel=True)
38 | query = self._process_dir(self.query_dir, relabel=False)
39 | gallery = self._process_dir(self.gallery_dir, relabel=False)
40 |
41 | if verbose:
42 | print("=> Market1501 loaded")
43 | self.print_dataset_statistics(train, query, gallery)
44 |
45 | self.train = train
46 | self.query = query
47 | self.gallery = gallery
48 |
49 | self.num_train_pids, self.num_train_imgs, self.num_train_cams = self.get_imagedata_info(self.train)
50 | self.num_query_pids, self.num_query_imgs, self.num_query_cams = self.get_imagedata_info(self.query)
51 | self.num_gallery_pids, self.num_gallery_imgs, self.num_gallery_cams = self.get_imagedata_info(self.gallery)
52 |
53 | def _check_before_run(self):
54 | """Check if all files are available before going deeper"""
55 | if not osp.exists(self.dataset_dir):
56 | raise RuntimeError("'{}' is not available".format(self.dataset_dir))
57 | if not osp.exists(self.train_dir):
58 | raise RuntimeError("'{}' is not available".format(self.train_dir))
59 | if not osp.exists(self.query_dir):
60 | raise RuntimeError("'{}' is not available".format(self.query_dir))
61 | if not osp.exists(self.gallery_dir):
62 | raise RuntimeError("'{}' is not available".format(self.gallery_dir))
63 |
64 | def _process_dir(self, dir_path, relabel=False):
65 | img_paths = glob.glob(osp.join(dir_path, '*.jpg'))
66 | pattern = re.compile(r'([-\d]+)_c(\d)')
67 |
68 | pid_container = set()
69 | for img_path in img_paths:
70 | pid, _ = map(int, pattern.search(img_path).groups())
71 | if pid == -1: continue # junk images are just ignored
72 | pid_container.add(pid)
73 | pid2label = {pid: label for label, pid in enumerate(pid_container)}
74 |
75 | dataset = []
76 | for img_path in img_paths:
77 | pid, camid = map(int, pattern.search(img_path).groups())
78 | if pid == -1: continue # junk images are just ignored
79 | assert 0 <= pid <= 1501 # pid == 0 means background
80 | assert 1 <= camid <= 6
81 | camid -= 1 # index starts from 0
82 | if relabel: pid = pid2label[pid]
83 | dataset.append((img_path, pid, camid))
84 |
85 | return dataset
86 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/data/datasets/ranking.py:
--------------------------------------------------------------------------------
1 | from __future__ import absolute_import
2 | from collections import defaultdict
3 | import torch
4 | import numpy as np
5 | from sklearn.metrics import average_precision_score
6 |
7 | def to_numpy(tensor):
8 | if torch.is_tensor(tensor):
9 | return tensor.cpu().numpy()
10 | elif type(tensor).__module__ != 'numpy':
11 | raise ValueError("Cannot convert {} to numpy array"
12 | .format(type(tensor)))
13 | return tensor
14 |
15 | def _unique_sample(ids_dict, num):
16 | mask = np.zeros(num, dtype=np.bool)
17 | for _, indices in ids_dict.items():
18 | i = np.random.choice(indices)
19 | mask[i] = True
20 | return mask
21 |
22 |
23 | def cmc(distmat, query_ids=None, gallery_ids=None,
24 | query_cams=None, gallery_cams=None, topk=100,
25 | separate_camera_set=False,
26 | single_gallery_shot=False,
27 | first_match_break=True):
28 | distmat = to_numpy(distmat)
29 | m, n = distmat.shape
30 | # Fill up default values
31 | if query_ids is None:
32 | query_ids = np.arange(m)
33 | if gallery_ids is None:
34 | gallery_ids = np.arange(n)
35 | if query_cams is None:
36 | query_cams = np.zeros(m).astype(np.int32)
37 | if gallery_cams is None:
38 | gallery_cams = np.ones(n).astype(np.int32)
39 | # Ensure numpy array
40 | query_ids = np.asarray(query_ids)
41 | gallery_ids = np.asarray(gallery_ids)
42 | query_cams = np.asarray(query_cams)
43 | gallery_cams = np.asarray(gallery_cams)
44 | # Sort and find correct matches
45 | indices = np.argsort(distmat, axis=1)
46 | matches = (gallery_ids[indices] == query_ids[:, np.newaxis])
47 | # Compute CMC for each query
48 | ret = np.zeros(topk)
49 | num_valid_queries = 0
50 | for i in range(m):
51 | # Filter out the same id and same camera
52 | valid = ((gallery_ids[indices[i]] != query_ids[i]) |
53 | (gallery_cams[indices[i]] != query_cams[i]))
54 | if separate_camera_set:
55 | # Filter out samples from same camera
56 | valid &= (gallery_cams[indices[i]] != query_cams[i])
57 | if not np.any(matches[i, valid]): continue
58 | if single_gallery_shot:
59 | repeat = 10
60 | gids = gallery_ids[indices[i][valid]]
61 | inds = np.where(valid)[0]
62 | ids_dict = defaultdict(list)
63 | for j, x in zip(inds, gids):
64 | ids_dict[x].append(j)
65 | else:
66 | repeat = 1
67 | for _ in range(repeat):
68 | if single_gallery_shot:
69 | # Randomly choose one instance for each id
70 | sampled = (valid & _unique_sample(ids_dict, len(valid)))
71 | index = np.nonzero(matches[i, sampled])[0]
72 | else:
73 | index = np.nonzero(matches[i, valid])[0]
74 | delta = 1. / (len(index) * repeat)
75 | for j, k in enumerate(index):
76 | if k - j >= topk: break
77 | if first_match_break:
78 | ret[k - j] += 1
79 | break
80 | ret[k - j] += delta
81 | num_valid_queries += 1
82 | if num_valid_queries == 0:
83 | raise RuntimeError("No valid query")
84 | return ret.cumsum() / num_valid_queries
85 |
86 |
87 | def mean_ap(distmat, query_ids=None, gallery_ids=None,
88 | query_cams=None, gallery_cams=None):
89 | distmat = to_numpy(distmat)
90 | m, n = distmat.shape
91 | # Fill up default values
92 | if query_ids is None:
93 | query_ids = np.arange(m)
94 | if gallery_ids is None:
95 | gallery_ids = np.arange(n)
96 | if query_cams is None:
97 | query_cams = np.zeros(m).astype(np.int32)
98 | if gallery_cams is None:
99 | gallery_cams = np.ones(n).astype(np.int32)
100 | # Ensure numpy array
101 | query_ids = np.asarray(query_ids)
102 | gallery_ids = np.asarray(gallery_ids)
103 | query_cams = np.asarray(query_cams)
104 | gallery_cams = np.asarray(gallery_cams)
105 | # Sort and find correct matches
106 | indices = np.argsort(distmat, axis=1)
107 | matches = (gallery_ids[indices] == query_ids[:, np.newaxis])
108 | # Compute AP for each query
109 | aps = []
110 | for i in range(m):
111 | # Filter out the same id and same camera
112 | valid = ((gallery_ids[indices[i]] != query_ids[i]) |
113 | (gallery_cams[indices[i]] != query_cams[i]))
114 | y_true = matches[i, valid]
115 | y_score = -distmat[i][indices[i]][valid]
116 | if not np.any(y_true): continue
117 | aps.append(average_precision_score(y_true, y_score))
118 | if len(aps) == 0:
119 | raise RuntimeError("No valid query")
120 | return np.mean(aps)
121 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/data/samplers/__init__.py:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | """
3 | @author: liaoxingyu
4 | @contact: sherlockliao01@gmail.com
5 | """
6 |
7 | from .triplet_sampler import RandomIdentitySampler
8 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/data/samplers/triplet_sampler.py:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | """
3 | @author: liaoxingyu
4 | @contact: liaoxingyu2@jd.com
5 | """
6 |
7 | import copy
8 | import random
9 | from collections import defaultdict
10 |
11 | import numpy as np
12 | from torch.utils.data.sampler import Sampler
13 |
14 |
15 | class RandomIdentitySampler(Sampler):
16 | """
17 | Randomly sample N identities, then for each identity,
18 | randomly sample K instances, therefore batch size is N*K.
19 | Args:
20 | - data_source (list): list of (img_path, pid, camid).
21 | - num_instances (int): number of instances per identity in a batch.
22 | - batch_size (int): number of examples in a batch.
23 | """
24 |
25 | def __init__(self, data_source, batch_size, num_instances):
26 | self.data_source = data_source
27 | self.batch_size = batch_size
28 | self.num_instances = num_instances
29 | self.num_pids_per_batch = self.batch_size // self.num_instances
30 | self.index_dic = defaultdict(list)
31 | for index, (_, pid, _) in enumerate(self.data_source):
32 | self.index_dic[pid].append(index)
33 | self.pids = list(self.index_dic.keys())
34 |
35 | # estimate number of examples in an epoch
36 | self.length = 0
37 | for pid in self.pids:
38 | idxs = self.index_dic[pid]
39 | num = len(idxs)
40 | if num < self.num_instances:
41 | num = self.num_instances
42 | self.length += num - num % self.num_instances
43 |
44 | def __iter__(self):
45 | batch_idxs_dict = defaultdict(list)
46 |
47 | for pid in self.pids:
48 | idxs = copy.deepcopy(self.index_dic[pid])
49 | if len(idxs) < self.num_instances:
50 | idxs = np.random.choice(idxs, size=self.num_instances, replace=True)
51 | random.shuffle(idxs)
52 | batch_idxs = []
53 | for idx in idxs:
54 | batch_idxs.append(idx)
55 | if len(batch_idxs) == self.num_instances:
56 | batch_idxs_dict[pid].append(batch_idxs)
57 | batch_idxs = []
58 |
59 | avai_pids = copy.deepcopy(self.pids)
60 | final_idxs = []
61 |
62 | while len(avai_pids) >= self.num_pids_per_batch:
63 | selected_pids = random.sample(avai_pids, self.num_pids_per_batch)
64 | for pid in selected_pids:
65 | batch_idxs = batch_idxs_dict[pid].pop(0)
66 | final_idxs.extend(batch_idxs)
67 | if len(batch_idxs_dict[pid]) == 0:
68 | avai_pids.remove(pid)
69 |
70 | return iter(final_idxs)
71 |
72 | def __len__(self):
73 | return self.length
74 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/data/transforms/__init__.py:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | """
3 | @author: sherlock
4 | @contact: sherlockliao01@gmail.com
5 | """
6 |
7 | from .build import build_transforms
8 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/data/transforms/build.py:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | """
3 | @author: weijian
4 | @contact: dengwj16@gmail.com
5 | """
6 |
7 | import torchvision.transforms as T
8 |
9 | import torch
10 |
11 | def build_transforms(cfg, is_train=True):
12 | normalize_transform = T.Normalize(mean=cfg.INPUT.PIXEL_MEAN, std=cfg.INPUT.PIXEL_STD)
13 | if is_train:
14 | transform = T.Compose([
15 | T.Resize(cfg.INPUT.SIZE_TRAIN),
16 | T.RandomHorizontalFlip(p=cfg.INPUT.PROB),
17 | T.Pad(cfg.INPUT.PADDING), # pad=10
18 | T.RandomCrop([256, 256]),
19 | T.ToTensor(),
20 | normalize_transform
21 | ])
22 |
23 | if is_train and cfg.INPUT.COLORJITTER:
24 | transform = T.Compose([
25 | T.Resize(cfg.INPUT.SIZE_TRAIN),
26 | T.RandomHorizontalFlip(p=cfg.INPUT.PROB),
27 | T.Pad(cfg.INPUT.PADDING), # pad=10
28 | T.RandomCrop([256, 256]),
29 | T.ColorJitter(brightness=0.1, contrast=0.1, saturation=0.1, hue=0),# light
30 | T.ToTensor(),
31 | normalize_transform
32 | ])
33 | else:
34 | #cfg.INPUT.SIZE_TEST
35 | transform = T.Compose([
36 | T.Resize(cfg.INPUT.SIZE_TEST),
37 | T.ToTensor(),
38 | normalize_transform
39 | ])
40 |
41 | return transform
42 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/data/transforms/transforms.py:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | """
3 | @author: liaoxingyu
4 | @contact: liaoxingyu2@jd.com
5 | """
6 |
7 | import math
8 | import random
9 |
10 |
11 | class RandomErasing(object):
12 | """ Randomly selects a rectangle region in an image and erases its pixels.
13 | 'Random Erasing Data Augmentation' by Zhong et al.
14 | See https://arxiv.org/pdf/1708.04896.pdf
15 | Args:
16 | probability: The probability that the Random Erasing operation will be performed.
17 | sl: Minimum proportion of erased area against input image.
18 | sh: Maximum proportion of erased area against input image.
19 | r1: Minimum aspect ratio of erased area.
20 | mean: Erasing value.
21 | """
22 |
23 | def __init__(self, probability=0.5, sl=0.02, sh=0.4, r1=0.3, mean=(0.4914, 0.4822, 0.4465)):
24 | self.probability = probability
25 | self.mean = mean
26 | self.sl = sl
27 | self.sh = sh
28 | self.r1 = r1
29 |
30 | def __call__(self, img):
31 |
32 | if random.uniform(0, 1) > self.probability:
33 | return img
34 |
35 | for attempt in range(100):
36 | area = img.size()[1] * img.size()[2]
37 |
38 | target_area = random.uniform(self.sl, self.sh) * area
39 | aspect_ratio = random.uniform(self.r1, 1 / self.r1)
40 |
41 | h = int(round(math.sqrt(target_area * aspect_ratio)))
42 | w = int(round(math.sqrt(target_area / aspect_ratio)))
43 |
44 | if w < img.size()[2] and h < img.size()[1]:
45 | x1 = random.randint(0, img.size()[1] - h)
46 | y1 = random.randint(0, img.size()[2] - w)
47 | if img.size()[0] == 3:
48 | img[0, x1:x1 + h, y1:y1 + w] = self.mean[0]
49 | img[1, x1:x1 + h, y1:y1 + w] = self.mean[1]
50 | img[2, x1:x1 + h, y1:y1 + w] = self.mean[2]
51 | else:
52 | img[0, x1:x1 + h, y1:y1 + w] = self.mean[0]
53 | return img
54 |
55 | return img
56 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/engine/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Simon4Yan/feature_learning/23ecc1bb2ce3ce4bece9159ca4ecc420e3e8f34c/Feature_Learning/learning_model/engine/__init__.py
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/engine/__init__.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Simon4Yan/feature_learning/23ecc1bb2ce3ce4bece9159ca4ecc420e3e8f34c/Feature_Learning/learning_model/engine/__init__.pyc
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/engine/__pycache__/__init__.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Simon4Yan/feature_learning/23ecc1bb2ce3ce4bece9159ca4ecc420e3e8f34c/Feature_Learning/learning_model/engine/__pycache__/__init__.cpython-37.pyc
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/engine/__pycache__/inference.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Simon4Yan/feature_learning/23ecc1bb2ce3ce4bece9159ca4ecc420e3e8f34c/Feature_Learning/learning_model/engine/__pycache__/inference.cpython-37.pyc
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/engine/__pycache__/trainer.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Simon4Yan/feature_learning/23ecc1bb2ce3ce4bece9159ca4ecc420e3e8f34c/Feature_Learning/learning_model/engine/__pycache__/trainer.cpython-37.pyc
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/engine/inference.py:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | """
3 | @author: sherlock
4 | @contact: sherlockliao01@gmail.com
5 | """
6 | import logging
7 |
8 | import torch
9 | from ignite.engine import Engine
10 |
11 | from utils.reid_metric import R1_mAP
12 | import scipy.io
13 |
14 | def create_supervised_evaluator(model, metrics,
15 | device=None):
16 | """
17 | Factory function for creating an evaluator for supervised models
18 |
19 | Args:
20 | model (`torch.nn.Module`): the model to train
21 | metrics (dict of str - :class:`ignite.metrics.Metric`): a map of metric names to Metrics
22 | device (str, optional): device type specification (default: None).
23 | Applies to both model and batches.
24 | Returns:
25 | Engine: an evaluator engine with supervised inference function
26 | """
27 | if device:
28 | model.to(device)
29 |
30 | def _inference(engine, batch):
31 | model.eval()
32 | with torch.no_grad():
33 | data, pids, camids = batch
34 | data = data.cuda()
35 | feat = model(data)
36 | return feat, pids, camids
37 |
38 | engine = Engine(_inference)
39 |
40 | for name, metric in metrics.items():
41 | metric.attach(engine, name)
42 |
43 | return engine
44 |
45 |
46 | def inference(
47 | cfg,
48 | model,
49 | val_loader,
50 | num_query
51 | ):
52 | device = cfg.MODEL.DEVICE
53 |
54 | logger = logging.getLogger("reid_baseline.inference")
55 | logger.info("Start inferencing")
56 | evaluator = create_supervised_evaluator(model, metrics={'r1_mAP': R1_mAP(num_query)},
57 | device=device)
58 |
59 | evaluator.run(val_loader)
60 | cmc, mAP = evaluator.state.metrics['r1_mAP']
61 | logger.info('Validation Results')
62 | logger.info("mAP: {:.1%}".format(mAP))
63 | for r in [1, 5, 10]:
64 | logger.info("CMC curve, Rank-{:<3}:{:.1%}".format(r, cmc[r - 1]))
65 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/engine/inference.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Simon4Yan/feature_learning/23ecc1bb2ce3ce4bece9159ca4ecc420e3e8f34c/Feature_Learning/learning_model/engine/inference.pyc
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/engine/trainer.py:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | """
3 | @author: sherlock
4 | @contact: sherlockliao01@gmail.com
5 | """
6 |
7 | import logging
8 |
9 | import torch
10 | import torch.nn as nn
11 | from ignite.engine import Engine, Events
12 | from ignite.handlers import ModelCheckpoint, Timer
13 | from ignite.metrics import RunningAverage
14 |
15 | from utils.reid_metric import R1_mAP
16 |
17 |
18 | def create_supervised_trainer(model, optimizer, loss_fn,
19 | device=None):
20 | """
21 | Factory function for creating a trainer for supervised models
22 |
23 | Args:
24 | model (`torch.nn.Module`): the model to train
25 | optimizer (`torch.optim.Optimizer`): the optimizer to use
26 | loss_fn (torch.nn loss function): the loss function to use
27 | device (str, optional): device type specification (default: None).
28 | Applies to both model and batches.
29 |
30 | Returns:
31 | Engine: a trainer engine with supervised update function
32 | """
33 | if device:
34 | model.to(device)
35 |
36 | def _update(engine, batch):
37 | model.train()
38 | '''
39 | for m in model.base.modules():
40 | if isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)):
41 | m.eval()
42 | m.weight.requires_grad = False
43 | m.bias.requires_grad = False
44 | '''
45 | optimizer.zero_grad()
46 | img, target = batch
47 | img = img.cuda()
48 | target = target.cuda()
49 | score, feat = model(img) # fuse batch size and ncrops
50 | loss = loss_fn(score, feat, target)
51 | loss.backward()
52 | optimizer.step()
53 | # compute acc
54 | acc = (score.max(1)[1] == target).float().mean()
55 | return loss.item(), acc.item()
56 |
57 | return Engine(_update)
58 |
59 |
60 | def create_supervised_evaluator(model, metrics,
61 | device=None):
62 | """
63 | Factory function for creating an evaluator for supervised models
64 |
65 | Args:
66 | model (`torch.nn.Module`): the model to train
67 | metrics (dict of str - :class:`ignite.metrics.Metric`): a map of metric names to Metrics
68 | device (str, optional): device type specification (default: None).
69 | Applies to both model and batches.
70 | Returns:
71 | Engine: an evaluator engine with supervised inference function
72 | """
73 | if device:
74 | model.to(device)
75 |
76 | def _inference(engine, batch):
77 | model.eval()
78 | with torch.no_grad():
79 | data, pids, camids = batch
80 | data = data.cuda()
81 | feat = model(data)
82 | return feat, pids, camids
83 |
84 | engine = Engine(_inference)
85 |
86 | for name, metric in metrics.items():
87 | metric.attach(engine, name)
88 |
89 | return engine
90 |
91 |
92 | def do_train(
93 | cfg,
94 | model,
95 | train_loader,
96 | val_loader,
97 | optimizer,
98 | scheduler,
99 | loss_fn,
100 | num_query
101 | ):
102 | log_period = cfg.SOLVER.LOG_PERIOD
103 | checkpoint_period = cfg.SOLVER.CHECKPOINT_PERIOD
104 | eval_period = cfg.SOLVER.EVAL_PERIOD
105 | output_dir = cfg.OUTPUT_DIR
106 | device = cfg.MODEL.DEVICE
107 | epochs = cfg.SOLVER.MAX_EPOCHS
108 |
109 | logger = logging.getLogger("reid_baseline.train")
110 | logger.info("Start training")
111 | trainer = create_supervised_trainer(model, optimizer, loss_fn, device=device)
112 | evaluator = create_supervised_evaluator(model, metrics={'r1_mAP': R1_mAP(num_query)}, device=device)
113 | checkpointer = ModelCheckpoint(output_dir, cfg.MODEL.NAME, checkpoint_period, n_saved=10, require_empty=False)
114 | timer = Timer(average=True)
115 |
116 | trainer.add_event_handler(Events.EPOCH_COMPLETED, checkpointer, {'model': model.state_dict(),
117 | 'optimizer': optimizer.state_dict()})
118 | timer.attach(trainer, start=Events.EPOCH_STARTED, resume=Events.ITERATION_STARTED,
119 | pause=Events.ITERATION_COMPLETED, step=Events.ITERATION_COMPLETED)
120 |
121 | # average metric to attach on trainer
122 | RunningAverage(output_transform=lambda x: x[0]).attach(trainer, 'avg_loss')
123 | RunningAverage(output_transform=lambda x: x[1]).attach(trainer, 'avg_acc')
124 |
125 | @trainer.on(Events.EPOCH_STARTED)
126 | def adjust_learning_rate(engine):
127 | scheduler.step()
128 |
129 | @trainer.on(Events.ITERATION_COMPLETED)
130 | def log_training_loss(engine):
131 | iter = (engine.state.iteration - 1) % len(train_loader) + 1
132 |
133 | if iter % log_period == 0:
134 | logger.info("Epoch[{}] Iteration[{}/{}] Loss: {:.3f}, Acc: {:.3f}, Base Lr: {:.2e}"
135 | .format(engine.state.epoch, iter, len(train_loader),
136 | engine.state.metrics['avg_loss'], engine.state.metrics['avg_acc'],
137 | scheduler.get_lr()[0]))
138 |
139 | # adding handlers using `trainer.on` decorator API
140 | @trainer.on(Events.EPOCH_COMPLETED)
141 | def print_times(engine):
142 | logger.info('Epoch {} done. Time per batch: {:.3f}[s] Speed: {:.1f}[samples/s]'
143 | .format(engine.state.epoch, timer.value() * timer.step_count,
144 | train_loader.batch_size / timer.value()))
145 | logger.info('-' * 10)
146 | timer.reset()
147 |
148 | @trainer.on(Events.EPOCH_COMPLETED)
149 | def log_validation_results(engine):
150 | if engine.state.epoch % eval_period == 0:
151 | evaluator.run(val_loader)
152 | cmc, mAP = evaluator.state.metrics['r1_mAP']
153 | logger.info("Validation Results - Epoch: {}".format(engine.state.epoch))
154 | logger.info("mAP: {:.1%}".format(mAP))
155 | for r in [1, 5, 10]:
156 | logger.info("CMC curve, Rank-{:<3}:{:.1%}".format(r, cmc[r - 1]))
157 |
158 | trainer.run(train_loader, max_epochs=epochs)
159 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/engine/trainer.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Simon4Yan/feature_learning/23ecc1bb2ce3ce4bece9159ca4ecc420e3e8f34c/Feature_Learning/learning_model/engine/trainer.pyc
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/layers/GHMC_Loss.py:
--------------------------------------------------------------------------------
1 | import torch
2 | import torch.nn.functional as F
3 |
4 |
5 | class GHMC_Loss:
6 | def __init__(self, bins=10, momentum=0):
7 | self.bins = bins
8 | self.momentum = momentum
9 | self.edges = [float(x) / bins for x in range(bins+1)]
10 | self.edges[-1] += 1e-6
11 | if momentum > 0:
12 | self.acc_sum = [0.0 for _ in range(bins)]
13 |
14 | def calc(self, input, target):
15 | """ Args:
16 | input [batch_num, class_num]:
17 | The direct prediction of classification fc layer.
18 | target [batch_num, class_num]:
19 | Binary target (0 or 1) for each sample each class. The value is -1
20 | when the sample is ignored.
21 | """
22 | edges = self.edges
23 | mmt = self.momentum
24 | weights = torch.zeros_like(input)
25 |
26 | temp = torch.zeros(input.size(0), input.size(1))
27 | target_onehot = temp.scatter_(1, target.cpu().view(-1, 1), 1).cuda()
28 | # gradient length
29 | g = torch.abs(input.sigmoid().detach() - target_onehot)
30 |
31 | #valid = mask > 0
32 | #tot = max(valid.float().sum().item(), 1.0)
33 | tot = input.size(0)
34 | n = 0 # n valid bins
35 | for i in range(self.bins):
36 | inds = (g >= edges[i]) & (g < edges[i+1]) #& valid
37 | num_in_bin = inds.sum().item()
38 | if num_in_bin > 0:
39 | if mmt > 0:
40 | self.acc_sum[i] = mmt * self.acc_sum[i] \
41 | + (1 - mmt) * num_in_bin
42 | weights[inds] = tot / self.acc_sum[i]
43 | else:
44 | weights[inds] = tot / num_in_bin
45 | n += 1
46 | if n > 0:
47 | weights = weights / n
48 |
49 | loss = F.binary_cross_entropy_with_logits(
50 | input, target_onehot, weights, reduction='sum') / tot
51 | return loss
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/layers/LabelSmoothing.py:
--------------------------------------------------------------------------------
1 |
2 | import torch
3 | import torch.nn as nn
4 |
5 |
6 | class LSR(nn.Module):
7 |
8 | def __init__(self, e=0.1, reduction='mean'):
9 | super().__init__()
10 |
11 | self.log_softmax = nn.LogSoftmax(dim=1)
12 | self.e = e
13 | self.reduction = reduction
14 |
15 | def _one_hot(self, labels, classes, value=1):
16 | """
17 | Convert labels to one hot vectors
18 |
19 | Args:
20 | labels: torch tensor in format [label1, label2, label3, ...]
21 | classes: int, number of classes
22 | value: label value in one hot vector, default to 1
23 |
24 | Returns:
25 | return one hot format labels in shape [batchsize, classes]
26 | """
27 |
28 | one_hot = torch.zeros(labels.size(0), classes)
29 |
30 | #labels and value_added size must match
31 | labels = labels.view(labels.size(0), -1)
32 | value_added = torch.Tensor(labels.size(0), 1).fill_(value)
33 |
34 | value_added = value_added.to(labels.device)
35 | one_hot = one_hot.to(labels.device)
36 |
37 | one_hot.scatter_add_(1, labels, value_added)
38 |
39 | return one_hot
40 |
41 | def _smooth_label(self, target, length, smooth_factor):
42 | """convert targets to one-hot format, and smooth
43 | them.
44 |
45 | Args:
46 | target: target in form with [label1, label2, label_batchsize]
47 | length: length of one-hot format(number of classes)
48 | smooth_factor: smooth factor for label smooth
49 |
50 | Returns:
51 | smoothed labels in one hot format
52 | """
53 | one_hot = self._one_hot(target, length, value=1 - smooth_factor)
54 | one_hot += smooth_factor / length
55 |
56 | return one_hot.to(target.device)
57 |
58 | def forward(self, x, target):
59 |
60 | if x.size(0) != target.size(0):
61 | raise ValueError('Expected input batchsize ({}) to match target batch_size({})'
62 | .format(x.size(0), target.size(0)))
63 |
64 | if x.dim() < 2:
65 | raise ValueError('Expected input tensor to have least 2 dimensions(got {})'
66 | .format(x.size(0)))
67 |
68 | if x.dim() != 2:
69 | raise ValueError('Only 2 dimension tensor are implemented, (got {})'
70 | .format(x.size()))
71 |
72 |
73 | smoothed_target = self._smooth_label(target, x.size(1), self.e)
74 | x = self.log_softmax(x)
75 | loss = torch.sum(- x * smoothed_target, dim=1)
76 |
77 | if self.reduction == 'none':
78 | return loss
79 |
80 | elif self.reduction == 'sum':
81 | return torch.sum(loss)
82 |
83 | elif self.reduction == 'mean':
84 | return torch.mean(loss)
85 |
86 | else:
87 | raise ValueError('unrecognized option, expect reduction to be one of none, mean, sum')
88 |
89 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/layers/__init__.py:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | """
3 | @author: liaoxingyu
4 | @contact: sherlockliao01@gmail.com
5 | """
6 |
7 | import torch.nn.functional as F
8 |
9 | from .triplet_loss import TripletLoss
10 | from .LabelSmoothing import LSR
11 | from .GHMC_Loss import GHMC_Loss
12 |
13 | def make_loss(cfg):
14 | sampler = cfg.DATALOADER.SAMPLER
15 | if cfg.DATALOADER.SOFT_MARGIN:
16 | triplet = TripletLoss()
17 | else:
18 | triplet = TripletLoss(cfg.SOLVER.MARGIN)
19 | lsr_loss = LSR()
20 | G_Loss = GHMC_Loss()
21 | if sampler == 'softmax':
22 | def loss_func(score, feat, target):
23 | return F.cross_entropy(score, target)
24 | elif cfg.DATALOADER.SAMPLER == 'triplet':
25 | def loss_func(score, feat, target):
26 | return triplet(feat, target)[0]
27 | elif cfg.DATALOADER.SAMPLER == 'softmax_triplet':
28 | def loss_func(score, feat, target):
29 | return lsr_loss(score, target) + triplet(feat, target)[0]
30 | else:
31 | print('expected sampler should be softmax, triplet or softmax_triplet, '
32 | 'but got {}'.format(cfg.DATALOADER.SAMPLER))
33 | return loss_func
34 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/layers/__pycache__/GHMC_Loss.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Simon4Yan/feature_learning/23ecc1bb2ce3ce4bece9159ca4ecc420e3e8f34c/Feature_Learning/learning_model/layers/__pycache__/GHMC_Loss.cpython-37.pyc
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/layers/__pycache__/LabelSmoothing.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Simon4Yan/feature_learning/23ecc1bb2ce3ce4bece9159ca4ecc420e3e8f34c/Feature_Learning/learning_model/layers/__pycache__/LabelSmoothing.cpython-37.pyc
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/layers/__pycache__/__init__.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Simon4Yan/feature_learning/23ecc1bb2ce3ce4bece9159ca4ecc420e3e8f34c/Feature_Learning/learning_model/layers/__pycache__/__init__.cpython-37.pyc
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/layers/__pycache__/triplet_loss.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Simon4Yan/feature_learning/23ecc1bb2ce3ce4bece9159ca4ecc420e3e8f34c/Feature_Learning/learning_model/layers/__pycache__/triplet_loss.cpython-37.pyc
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/layers/triplet_loss.py:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | """
3 | @author: liaoxingyu
4 | @contact: sherlockliao01@gmail.com
5 | """
6 | import torch
7 | from torch import nn
8 |
9 |
10 | def normalize(x, axis=-1):
11 | """Normalizing to unit length along the specified dimension.
12 | Args:
13 | x: pytorch Variable
14 | Returns:
15 | x: pytorch Variable, same shape as input
16 | """
17 | x = 1. * x / (torch.norm(x, 2, axis, keepdim=True).expand_as(x) + 1e-12)
18 | return x
19 |
20 |
21 | def euclidean_dist(x, y):
22 | """
23 | Args:
24 | x: pytorch Variable, with shape [m, d]
25 | y: pytorch Variable, with shape [n, d]
26 | Returns:
27 | dist: pytorch Variable, with shape [m, n]
28 | """
29 | m, n = x.size(0), y.size(0)
30 | xx = torch.pow(x, 2).sum(1, keepdim=True).expand(m, n)
31 | yy = torch.pow(y, 2).sum(1, keepdim=True).expand(n, m).t()
32 | dist = xx + yy
33 | dist.addmm_(1, -2, x, y.t())
34 | dist = dist.clamp(min=1e-12).sqrt() # for numerical stability
35 | return dist
36 |
37 |
38 | def hard_example_mining(dist_mat, labels, return_inds=False):
39 | """For each anchor, find the hardest positive and negative sample.
40 | Args:
41 | dist_mat: pytorch Variable, pair wise distance between samples, shape [N, N]
42 | labels: pytorch LongTensor, with shape [N]
43 | return_inds: whether to return the indices. Save time if `False`(?)
44 | Returns:
45 | dist_ap: pytorch Variable, distance(anchor, positive); shape [N]
46 | dist_an: pytorch Variable, distance(anchor, negative); shape [N]
47 | p_inds: pytorch LongTensor, with shape [N];
48 | indices of selected hard positive samples; 0 <= p_inds[i] <= N - 1
49 | n_inds: pytorch LongTensor, with shape [N];
50 | indices of selected hard negative samples; 0 <= n_inds[i] <= N - 1
51 | NOTE: Only consider the case in which all labels have same num of samples,
52 | thus we can cope with all anchors in parallel.
53 | """
54 |
55 | assert len(dist_mat.size()) == 2
56 | assert dist_mat.size(0) == dist_mat.size(1)
57 | N = dist_mat.size(0)
58 |
59 | # shape [N, N]
60 | is_pos = labels.expand(N, N).eq(labels.expand(N, N).t())
61 | is_neg = labels.expand(N, N).ne(labels.expand(N, N).t())
62 |
63 | # `dist_ap` means distance(anchor, positive)
64 | # both `dist_ap` and `relative_p_inds` with shape [N, 1]
65 | dist_ap, relative_p_inds = torch.max(
66 | dist_mat[is_pos].contiguous().view(N, -1), 1, keepdim=True)
67 | # `dist_an` means distance(anchor, negative)
68 | # both `dist_an` and `relative_n_inds` with shape [N, 1]
69 | dist_an, relative_n_inds = torch.min(
70 | dist_mat[is_neg].contiguous().view(N, -1), 1, keepdim=True)
71 | # shape [N]
72 | dist_ap = dist_ap.squeeze(1)
73 | dist_an = dist_an.squeeze(1)
74 |
75 | if return_inds:
76 | # shape [N, N]
77 | ind = (labels.new().resize_as_(labels)
78 | .copy_(torch.arange(0, N).long())
79 | .unsqueeze(0).expand(N, N))
80 | # shape [N, 1]
81 | p_inds = torch.gather(
82 | ind[is_pos].contiguous().view(N, -1), 1, relative_p_inds.data)
83 | n_inds = torch.gather(
84 | ind[is_neg].contiguous().view(N, -1), 1, relative_n_inds.data)
85 | # shape [N]
86 | p_inds = p_inds.squeeze(1)
87 | n_inds = n_inds.squeeze(1)
88 | return dist_ap, dist_an, p_inds, n_inds
89 |
90 | return dist_ap, dist_an
91 |
92 |
93 | class TripletLoss(object):
94 | """Modified from Tong Xiao's open-reid (https://github.com/Cysu/open-reid).
95 | Related Triplet Loss theory can be found in paper 'In Defense of the Triplet
96 | Loss for Person Re-Identification'."""
97 |
98 | def __init__(self, margin=None):
99 | self.margin = margin
100 | if margin is not None:
101 | self.ranking_loss = nn.MarginRankingLoss(margin=margin)
102 | else:
103 | self.ranking_loss = nn.SoftMarginLoss()
104 |
105 | def __call__(self, global_feat, labels, normalize_feature=False):
106 | if normalize_feature:
107 | global_feat = normalize(global_feat, axis=-1)
108 | dist_mat = euclidean_dist(global_feat, global_feat)
109 | dist_ap, dist_an = hard_example_mining(
110 | dist_mat, labels)
111 | y = dist_an.new().resize_as_(dist_an).fill_(1)
112 | if self.margin is not None:
113 | loss = self.ranking_loss(dist_an, dist_ap, y)
114 | else:
115 | loss = self.ranking_loss(dist_an - dist_ap, y)
116 | return loss, dist_ap, dist_an
117 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/modeling/__init__.py:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | """
3 | @author: sherlock
4 | @contact: sherlockliao01@gmail.com
5 | """
6 |
7 | from .baseline_de import Baseline_de
8 |
9 | def build_model(cfg, num_classes):
10 |
11 | if cfg.MODEL.NAME == 'densenet121':
12 | model = Baseline_de(num_classes, cfg.MODEL.LAST_STRIDE, cfg.MODEL.PRETRAIN_PATH)
13 |
14 | return model
15 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/modeling/backbones/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Simon4Yan/feature_learning/23ecc1bb2ce3ce4bece9159ca4ecc420e3e8f34c/Feature_Learning/learning_model/modeling/backbones/__init__.py
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/modeling/backbones/torchvision_models.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import print_function, division, absolute_import
3 | import torchvision.models as models
4 | import torch.utils.model_zoo as model_zoo
5 | import torch.nn.functional as F
6 | import types
7 | import re
8 | import torch
9 | #################################################################
10 | # You can find the definitions of those models here:
11 | # https://github.com/pytorch/vision/blob/master/torchvision/models
12 | #
13 | # To fit the API, we usually added/redefined some methods and
14 | # renamed some attributs (see below for each models).
15 | #
16 | # However, you usually do not need to see the original model
17 | # definition from torchvision. Just use `print(model)` to see
18 | # the modules and see bellow the `model.features` and
19 | # `model.classifier` definitions.
20 | #################################################################
21 |
22 | __all__ = [
23 | 'alexnet',
24 | 'densenet121', 'densenet169', 'densenet201', 'densenet161',
25 | 'resnet18', 'resnet34', 'resnet50', 'resnet101', 'resnet152',
26 | 'inceptionv3',
27 | 'squeezenet1_0', 'squeezenet1_1',
28 | 'vgg11', 'vgg11_bn', 'vgg13', 'vgg13_bn', 'vgg16', 'vgg16_bn',
29 | 'vgg19_bn', 'vgg19'
30 | ]
31 |
32 | model_urls = {
33 | 'alexnet': 'https://download.pytorch.org/models/alexnet-owt-4df8aa71.pth',
34 | 'densenet121': 'http://data.lip6.fr/cadene/pretrainedmodels/densenet121-fbdb23505.pth',
35 | 'densenet169': 'http://data.lip6.fr/cadene/pretrainedmodels/densenet169-f470b90a4.pth',
36 | 'densenet201': 'http://data.lip6.fr/cadene/pretrainedmodels/densenet201-5750cbb1e.pth',
37 | 'densenet161': 'http://data.lip6.fr/cadene/pretrainedmodels/densenet161-347e6b360.pth',
38 | 'inceptionv3': 'https://download.pytorch.org/models/inception_v3_google-1a9a5a14.pth',
39 | 'resnet18': 'https://download.pytorch.org/models/resnet18-5c106cde.pth',
40 | 'resnet34': 'https://download.pytorch.org/models/resnet34-333f7ec4.pth',
41 | 'resnet50': 'https://download.pytorch.org/models/resnet50-19c8e357.pth',
42 | 'resnet101': 'https://download.pytorch.org/models/resnet101-5d3b4d8f.pth',
43 | 'resnet152': 'https://download.pytorch.org/models/resnet152-b121ed2d.pth',
44 | 'squeezenet1_0': 'https://download.pytorch.org/models/squeezenet1_0-a815701f.pth',
45 | 'squeezenet1_1': 'https://download.pytorch.org/models/squeezenet1_1-f364aa15.pth',
46 | 'vgg11': 'https://download.pytorch.org/models/vgg11-bbd30ac9.pth',
47 | 'vgg13': 'https://download.pytorch.org/models/vgg13-c768596a.pth',
48 | 'vgg16': 'https://download.pytorch.org/models/vgg16-397923af.pth',
49 | 'vgg19': 'https://download.pytorch.org/models/vgg19-dcbb9e9d.pth',
50 | 'vgg11_bn': 'https://download.pytorch.org/models/vgg11_bn-6002323d.pth',
51 | 'vgg13_bn': 'https://download.pytorch.org/models/vgg13_bn-abd245e5.pth',
52 | 'vgg16_bn': 'https://download.pytorch.org/models/vgg16_bn-6c64b313.pth',
53 | 'vgg19_bn': 'https://download.pytorch.org/models/vgg19_bn-c79401a0.pth',
54 | # 'vgg16_caffe': 'https://s3-us-west-2.amazonaws.com/jcjohns-models/vgg16-00b39a1b.pth',
55 | # 'vgg19_caffe': 'https://s3-us-west-2.amazonaws.com/jcjohns-models/vgg19-d01eb7cb.pth'
56 | }
57 |
58 | input_sizes = {}
59 | means = {}
60 | stds = {}
61 |
62 | for model_name in __all__:
63 | input_sizes[model_name] = [3, 224, 224]
64 | means[model_name] = [0.485, 0.456, 0.406]
65 | stds[model_name] = [0.229, 0.224, 0.225]
66 |
67 | for model_name in ['inceptionv3']:
68 | input_sizes[model_name] = [3, 299, 299]
69 | means[model_name] = [0.5, 0.5, 0.5]
70 | stds[model_name] = [0.5, 0.5, 0.5]
71 |
72 | pretrained_settings = {}
73 |
74 | for model_name in __all__:
75 | pretrained_settings[model_name] = {
76 | 'imagenet': {
77 | 'url': model_urls[model_name],
78 | 'input_space': 'RGB',
79 | 'input_size': input_sizes[model_name],
80 | 'input_range': [0, 1],
81 | 'mean': means[model_name],
82 | 'std': stds[model_name],
83 | 'num_classes': 1000
84 | }
85 | }
86 |
87 | # for model_name in ['vgg16', 'vgg19']:
88 | # pretrained_settings[model_name]['imagenet_caffe'] = {
89 | # 'url': model_urls[model_name + '_caffe'],
90 | # 'input_space': 'BGR',
91 | # 'input_size': input_sizes[model_name],
92 | # 'input_range': [0, 255],
93 | # 'mean': [103.939, 116.779, 123.68],
94 | # 'std': [1., 1., 1.],
95 | # 'num_classes': 1000
96 | # }
97 |
98 | def update_state_dict(state_dict):
99 | # '.'s are no longer allowed in module names, but pervious _DenseLayer
100 | # has keys 'norm.1', 'relu.1', 'conv.1', 'norm.2', 'relu.2', 'conv.2'.
101 | # They are also in the checkpoints in model_urls. This pattern is used
102 | # to find such keys.
103 | pattern = re.compile(
104 | r'^(.*denselayer\d+\.(?:norm|relu|conv))\.((?:[12])\.(?:weight|bias|running_mean|running_var))$')
105 | for key in list(state_dict.keys()):
106 | res = pattern.match(key)
107 | if res:
108 | new_key = res.group(1) + res.group(2)
109 | state_dict[new_key] = state_dict[key]
110 | del state_dict[key]
111 | return state_dict
112 |
113 | def load_pretrained(model, num_classes, settings):
114 | assert num_classes == settings['num_classes'], \
115 | "num_classes should be {}, but is {}".format(settings['num_classes'], num_classes)
116 | state_dict = model_zoo.load_url(settings['url'])
117 | state_dict = update_state_dict(state_dict)
118 | model.load_state_dict(state_dict)
119 | model.input_space = settings['input_space']
120 | model.input_size = settings['input_size']
121 | model.input_range = settings['input_range']
122 | model.mean = settings['mean']
123 | model.std = settings['std']
124 | return model
125 |
126 | #################################################################
127 | # AlexNet
128 |
129 | def modify_alexnet(model):
130 | # Modify attributs
131 | model._features = model.features
132 | del model.features
133 | model.dropout0 = model.classifier[0]
134 | model.linear0 = model.classifier[1]
135 | model.relu0 = model.classifier[2]
136 | model.dropout1 = model.classifier[3]
137 | model.linear1 = model.classifier[4]
138 | model.relu1 = model.classifier[5]
139 | model.last_linear = model.classifier[6]
140 | del model.classifier
141 |
142 | def features(self, input):
143 | x = self._features(input)
144 | x = x.view(x.size(0), 256 * 6 * 6)
145 | x = self.dropout0(x)
146 | x = self.linear0(x)
147 | x = self.relu0(x)
148 | x = self.dropout1(x)
149 | x = self.linear1(x)
150 | return x
151 |
152 | def logits(self, features):
153 | x = self.relu1(features)
154 | x = self.last_linear(x)
155 | return x
156 |
157 | def forward(self, input):
158 | x = self.features(input)
159 | x = self.logits(x)
160 | return x
161 |
162 | # Modify methods
163 | model.features = types.MethodType(features, model)
164 | model.logits = types.MethodType(logits, model)
165 | model.forward = types.MethodType(forward, model)
166 | return model
167 |
168 | def alexnet(num_classes=1000, pretrained='imagenet'):
169 | r"""AlexNet model architecture from the
170 | `"One weird trick..." `_ paper.
171 | """
172 | # https://github.com/pytorch/vision/blob/master/torchvision/models/alexnet.py
173 | model = models.alexnet(pretrained=False)
174 | if pretrained is not None:
175 | settings = pretrained_settings['alexnet'][pretrained]
176 | model = load_pretrained(model, num_classes, settings)
177 | model = modify_alexnet(model)
178 | return model
179 |
180 | ###############################################################
181 | #DenseNets
182 |
183 | def modify_densenets(model):
184 | # Modify attributs
185 | model.last_linear = model.classifier
186 | del model.classifier
187 |
188 | def logits(self, features):
189 | x = F.relu(features, inplace=True)
190 | x = F.avg_pool2d(x, kernel_size=7, stride=1)
191 | x = x.view(x.size(0), -1)
192 | x = self.last_linear(x)
193 | return x
194 |
195 | def forward(self, input):
196 | x = self.features(input)
197 | #x = self.logits(x)
198 | return x
199 | # Modify methods
200 | model.logits = types.MethodType(logits, model)
201 | model.forward = types.MethodType(forward, model)
202 | return model
203 |
204 | def densenet121(num_classes=1000, pretrained='imagenet'):
205 | r"""Densenet-121 model from
206 | `"Densely Connected Convolutional Networks" `
207 | """
208 | model = models.densenet121(pretrained=True)
209 |
210 | if pretrained is not None:
211 | settings = pretrained_settings['densenet121'][pretrained]
212 | model = load_pretrained(model, num_classes, settings)
213 |
214 | model = modify_densenets(model)
215 | return model
216 |
217 |
218 |
219 |
220 | def densenet169(num_classes=1000, pretrained='imagenet'):
221 | r"""Densenet-169 model from
222 | `"Densely Connected Convolutional Networks" `
223 | """
224 | model = models.densenet169(pretrained=False)
225 | if pretrained is not None:
226 | settings = pretrained_settings['densenet169'][pretrained]
227 | model = load_pretrained(model, num_classes, settings)
228 | model = modify_densenets(model)
229 | return model
230 |
231 | def densenet201(num_classes=1000, pretrained='imagenet'):
232 | r"""Densenet-201 model from
233 | `"Densely Connected Convolutional Networks" `
234 | """
235 | model = models.densenet201(pretrained=False)
236 | if pretrained is not None:
237 | settings = pretrained_settings['densenet201'][pretrained]
238 | model = load_pretrained(model, num_classes, settings)
239 | model = modify_densenets(model)
240 | return model
241 |
242 | def densenet161(num_classes=1000, pretrained='imagenet'):
243 | r"""Densenet-161 model from
244 | `"Densely Connected Convolutional Networks" `
245 | """
246 | model = models.densenet161(pretrained=False)
247 | if pretrained is not None:
248 | settings = pretrained_settings['densenet161'][pretrained]
249 | model = load_pretrained(model, num_classes, settings)
250 | model = modify_densenets(model)
251 | return model
252 |
253 | ###############################################################
254 | # InceptionV3
255 |
256 | def inceptionv3(num_classes=1000, pretrained='imagenet'):
257 | r"""Inception v3 model architecture from
258 | `"Rethinking the Inception Architecture for Computer Vision" `_.
259 | """
260 | model = models.inception_v3(pretrained=False)
261 | if pretrained is not None:
262 | settings = pretrained_settings['inceptionv3'][pretrained]
263 | model = load_pretrained(model, num_classes, settings)
264 |
265 | # Modify attributs
266 | model.last_linear = model.fc
267 | del model.fc
268 |
269 | def features(self, input):
270 | # 299 x 299 x 3
271 | x = self.Conv2d_1a_3x3(input) # 149 x 149 x 32
272 | x = self.Conv2d_2a_3x3(x) # 147 x 147 x 32
273 | x = self.Conv2d_2b_3x3(x) # 147 x 147 x 64
274 | x = F.max_pool2d(x, kernel_size=3, stride=2) # 73 x 73 x 64
275 | x = self.Conv2d_3b_1x1(x) # 73 x 73 x 80
276 | x = self.Conv2d_4a_3x3(x) # 71 x 71 x 192
277 | x = F.max_pool2d(x, kernel_size=3, stride=2) # 35 x 35 x 192
278 | x = self.Mixed_5b(x) # 35 x 35 x 256
279 | x = self.Mixed_5c(x) # 35 x 35 x 288
280 | x = self.Mixed_5d(x) # 35 x 35 x 288
281 | x = self.Mixed_6a(x) # 17 x 17 x 768
282 | x = self.Mixed_6b(x) # 17 x 17 x 768
283 | x = self.Mixed_6c(x) # 17 x 17 x 768
284 | x = self.Mixed_6d(x) # 17 x 17 x 768
285 | x = self.Mixed_6e(x) # 17 x 17 x 768
286 | if self.training and self.aux_logits:
287 | self._out_aux = self.AuxLogits(x) # 17 x 17 x 768
288 | x = self.Mixed_7a(x) # 8 x 8 x 1280
289 | x = self.Mixed_7b(x) # 8 x 8 x 2048
290 | x = self.Mixed_7c(x) # 8 x 8 x 2048
291 | return x
292 |
293 | def logits(self, features):
294 | x = F.avg_pool2d(features, kernel_size=8) # 1 x 1 x 2048
295 | x = F.dropout(x, training=self.training) # 1 x 1 x 2048
296 | x = x.view(x.size(0), -1) # 2048
297 | x = self.last_linear(x) # 1000 (num_classes)
298 | if self.training and self.aux_logits:
299 | aux = self._out_aux
300 | self._out_aux = None
301 | return x, aux
302 | return x
303 |
304 | def forward(self, input):
305 | x = self.features(input)
306 | x = self.logits(x)
307 | return x
308 |
309 | # Modify methods
310 | model.features = types.MethodType(features, model)
311 | model.logits = types.MethodType(logits, model)
312 | model.forward = types.MethodType(forward, model)
313 | return model
314 |
315 | ###############################################################
316 | # ResNets
317 |
318 | def modify_resnets(model):
319 | # Modify attributs
320 | model.last_linear = model.fc
321 | model.fc = None
322 |
323 | def features(self, input):
324 | x = self.conv1(input)
325 | x = self.bn1(x)
326 | x = self.relu(x)
327 | x = self.maxpool(x)
328 |
329 | x = self.layer1(x)
330 | x = self.layer2(x)
331 | x = self.layer3(x)
332 | x = self.layer4(x)
333 | return x
334 |
335 | def logits(self, features):
336 | x = self.avgpool(features)
337 | x = x.view(x.size(0), -1)
338 | x = self.last_linear(x)
339 | return x
340 |
341 | def forward(self, input):
342 | x = self.features(input)
343 | #x = self.logits(x)
344 | return x
345 |
346 | # Modify methods
347 | model.features = types.MethodType(features, model)
348 | model.logits = types.MethodType(logits, model)
349 | model.forward = types.MethodType(forward, model)
350 | return model
351 |
352 | def resnet18(num_classes=1000, pretrained='imagenet'):
353 | """Constructs a ResNet-18 model.
354 | """
355 | model = models.resnet18(pretrained=False)
356 | if pretrained is not None:
357 | settings = pretrained_settings['resnet18'][pretrained]
358 | model = load_pretrained(model, num_classes, settings)
359 | model = modify_resnets(model)
360 | return model
361 |
362 | def resnet34(num_classes=1000, pretrained='imagenet'):
363 | """Constructs a ResNet-34 model.
364 | """
365 | model = models.resnet34(pretrained=False)
366 | if pretrained is not None:
367 | settings = pretrained_settings['resnet34'][pretrained]
368 | model = load_pretrained(model, num_classes, settings)
369 | model = modify_resnets(model)
370 | return model
371 |
372 | def resnet50(num_classes=1000, pretrained='imagenet'):
373 | """Constructs a ResNet-50 model.
374 | """
375 | model = models.resnet50(pretrained=False)
376 | if pretrained is not None:
377 | settings = pretrained_settings['resnet50'][pretrained]
378 | model = load_pretrained(model, num_classes, settings)
379 | model = modify_resnets(model)
380 | return model
381 |
382 | def resnet101(num_classes=1000, pretrained='imagenet'):
383 | """Constructs a ResNet-101 model.
384 | """
385 | model = models.resnet101(pretrained=False)
386 | if pretrained is not None:
387 | settings = pretrained_settings['resnet101'][pretrained]
388 | model = load_pretrained(model, num_classes, settings)
389 | model = modify_resnets(model)
390 | return model
391 |
392 | def resnet152(num_classes=1000, pretrained='imagenet'):
393 | """Constructs a ResNet-152 model.
394 | """
395 | model = models.resnet152(pretrained=False)
396 | #if pretrained is not None:
397 | # settings = pretrained_settings['resnet152'][pretrained]
398 | # model = load_pretrained(model, num_classes, settings)
399 | model = modify_resnets(model)
400 | return model
401 |
402 | ###############################################################
403 | # SqueezeNets
404 |
405 | def modify_squeezenets(model):
406 | # /!\ Beware squeezenets do not have any last_linear module
407 |
408 | # Modify attributs
409 | model.dropout = model.classifier[0]
410 | model.last_conv = model.classifier[1]
411 | model.relu = model.classifier[2]
412 | model.avgpool = model.classifier[3]
413 | del model.classifier
414 |
415 | def logits(self, features):
416 | x = self.dropout(features)
417 | x = self.last_conv(x)
418 | x = self.relu(x)
419 | x = self.avgpool(x)
420 | return x
421 |
422 | def forward(self, input):
423 | x = self.features(input)
424 | x = self.logits(x)
425 | return x
426 |
427 | # Modify methods
428 | model.logits = types.MethodType(logits, model)
429 | model.forward = types.MethodType(forward, model)
430 | return model
431 |
432 | def squeezenet1_0(num_classes=1000, pretrained='imagenet'):
433 | r"""SqueezeNet model architecture from the `"SqueezeNet: AlexNet-level
434 | accuracy with 50x fewer parameters and <0.5MB model size"
435 | `_ paper.
436 | """
437 | model = models.squeezenet1_0(pretrained=False)
438 | if pretrained is not None:
439 | settings = pretrained_settings['squeezenet1_0'][pretrained]
440 | model = load_pretrained(model, num_classes, settings)
441 | model = modify_squeezenets(model)
442 | return model
443 |
444 | def squeezenet1_1(num_classes=1000, pretrained='imagenet'):
445 | r"""SqueezeNet 1.1 model from the `official SqueezeNet repo
446 | `_.
447 | SqueezeNet 1.1 has 2.4x less computation and slightly fewer parameters
448 | than SqueezeNet 1.0, without sacrificing accuracy.
449 | """
450 | model = models.squeezenet1_1(pretrained=False)
451 | if pretrained is not None:
452 | settings = pretrained_settings['squeezenet1_1'][pretrained]
453 | model = load_pretrained(model, num_classes, settings)
454 | model = modify_squeezenets(model)
455 | return model
456 |
457 | ###############################################################
458 | # VGGs
459 |
460 | def modify_vggs(model):
461 | # Modify attributs
462 | model._features = model.features
463 | del model.features
464 | model.linear0 = model.classifier[0]
465 | model.relu0 = model.classifier[1]
466 | model.dropout0 = model.classifier[2]
467 | model.linear1 = model.classifier[3]
468 | model.relu1 = model.classifier[4]
469 | model.dropout1 = model.classifier[5]
470 | model.last_linear = model.classifier[6]
471 | del model.classifier
472 |
473 | def features(self, input):
474 | x = self._features(input)
475 | x = x.view(x.size(0), -1)
476 | x = self.linear0(x)
477 | x = self.relu0(x)
478 | x = self.dropout0(x)
479 | x = self.linear1(x)
480 | return x
481 |
482 | def logits(self, features):
483 | x = self.relu1(features)
484 | x = self.dropout1(x)
485 | x = self.last_linear(x)
486 | return x
487 |
488 | def forward(self, input):
489 | x = self.features(input)
490 | x = self.logits(x)
491 | return x
492 |
493 | # Modify methods
494 | model.features = types.MethodType(features, model)
495 | model.logits = types.MethodType(logits, model)
496 | model.forward = types.MethodType(forward, model)
497 | return model
498 |
499 | def vgg11(num_classes=1000, pretrained='imagenet'):
500 | """VGG 11-layer model (configuration "A")
501 | """
502 | model = models.vgg11(pretrained=False)
503 | if pretrained is not None:
504 | settings = pretrained_settings['vgg11'][pretrained]
505 | model = load_pretrained(model, num_classes, settings)
506 | model = modify_vggs(model)
507 | return model
508 |
509 | def vgg11_bn(num_classes=1000, pretrained='imagenet'):
510 | """VGG 11-layer model (configuration "A") with batch normalization
511 | """
512 | model = models.vgg11_bn(pretrained=False)
513 | if pretrained is not None:
514 | settings = pretrained_settings['vgg11_bn'][pretrained]
515 | model = load_pretrained(model, num_classes, settings)
516 | model = modify_vggs(model)
517 | return model
518 |
519 | def vgg13(num_classes=1000, pretrained='imagenet'):
520 | """VGG 13-layer model (configuration "B")
521 | """
522 | model = models.vgg13(pretrained=False)
523 | if pretrained is not None:
524 | settings = pretrained_settings['vgg13'][pretrained]
525 | model = load_pretrained(model, num_classes, settings)
526 | model = modify_vggs(model)
527 | return model
528 |
529 | def vgg13_bn(num_classes=1000, pretrained='imagenet'):
530 | """VGG 13-layer model (configuration "B") with batch normalization
531 | """
532 | model = models.vgg13_bn(pretrained=False)
533 | if pretrained is not None:
534 | settings = pretrained_settings['vgg13_bn'][pretrained]
535 | model = load_pretrained(model, num_classes, settings)
536 | model = modify_vggs(model)
537 | return model
538 |
539 | def vgg16(num_classes=1000, pretrained='imagenet'):
540 | """VGG 16-layer model (configuration "D")
541 | """
542 | model = models.vgg16(pretrained=False)
543 | if pretrained is not None:
544 | settings = pretrained_settings['vgg16'][pretrained]
545 | model = load_pretrained(model, num_classes, settings)
546 | model = modify_vggs(model)
547 | return model
548 |
549 | def vgg16_bn(num_classes=1000, pretrained='imagenet'):
550 | """VGG 16-layer model (configuration "D") with batch normalization
551 | """
552 | model = models.vgg16_bn(pretrained=False)
553 | if pretrained is not None:
554 | settings = pretrained_settings['vgg16_bn'][pretrained]
555 | model = load_pretrained(model, num_classes, settings)
556 | model = modify_vggs(model)
557 | return model
558 |
559 | def vgg19(num_classes=1000, pretrained='imagenet'):
560 | """VGG 19-layer model (configuration "E")
561 | """
562 | model = models.vgg19(pretrained=False)
563 | if pretrained is not None:
564 | settings = pretrained_settings['vgg19'][pretrained]
565 | model = load_pretrained(model, num_classes, settings)
566 | model = modify_vggs(model)
567 | return model
568 |
569 | def vgg19_bn(num_classes=1000, pretrained='imagenet'):
570 | """VGG 19-layer model (configuration 'E') with batch normalization
571 | """
572 | model = models.vgg19_bn(pretrained=False)
573 | if pretrained is not None:
574 | settings = pretrained_settings['vgg19_bn'][pretrained]
575 | model = load_pretrained(model, num_classes, settings)
576 | model = modify_vggs(model)
577 | return model
578 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/modeling/baseline_de.py:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | """
3 | @author: weijian
4 | @contact: dengwj16@gmail.com
5 | """
6 |
7 | from torch import nn
8 |
9 | from .backbones.torchvision_models import densenet121
10 |
11 | def weights_init_kaiming(m):
12 | classname = m.__class__.__name__
13 | if classname.find('Linear') != -1:
14 | nn.init.kaiming_normal_(m.weight, a=0, mode='fan_out')
15 | nn.init.constant_(m.bias, 0.0)
16 | elif classname.find('Conv') != -1:
17 | nn.init.kaiming_normal_(m.weight, a=0, mode='fan_in')
18 | if m.bias is not None:
19 | nn.init.constant_(m.bias, 0.0)
20 | elif classname.find('BatchNorm') != -1:
21 | if m.affine:
22 | nn.init.constant_(m.weight, 1.0)
23 | nn.init.constant_(m.bias, 0.0)
24 |
25 |
26 | def weights_init_classifier(m):
27 | classname = m.__class__.__name__
28 | if classname.find('Linear') != -1:
29 | nn.init.normal_(m.weight, std=0.001)
30 | if m.bias:
31 | nn.init.constant_(m.bias, 0.0)
32 |
33 | def freeze_bn(modules):
34 | for m in modules:
35 | if isinstance(m, (nn.BatchNorm2d, nn.GroupNorm)):
36 | m.eval()
37 | m.weight.requires_grad = False
38 | m.bias.requires_grad = False
39 |
40 | class Baseline_de(nn.Module):
41 | in_planes = 1024
42 |
43 | def __init__(self, num_classes, last_stride, model_path):
44 | super(Baseline_de, self).__init__()
45 | self.base = densenet121()
46 | self.base.features.transition3.pool=nn.Sequential()# stride
47 |
48 | self.gap = nn.AdaptiveAvgPool2d(1)
49 | self.num_bottleneck = 1024
50 | self.num_classes = num_classes
51 |
52 | add_block = []
53 | add_block += [nn.Linear(self.in_planes, self.num_bottleneck)]
54 | add_block += [nn.BatchNorm1d(self.num_bottleneck)]
55 | add_block = nn.Sequential(*add_block)
56 | self.bottleneck = add_block
57 | self.bottleneck.apply(weights_init_kaiming)
58 |
59 | self.classifier = nn.Linear(self.num_bottleneck, self.num_classes, bias=False)
60 | self.classifier.apply(weights_init_classifier)
61 |
62 | def forward(self, x):
63 | global_feat = self.gap(self.base(x)) # (b, 1024, 1, 1)
64 | global_feat = global_feat.view(global_feat.shape[0], -1) # flatten to (bs, 1024)
65 | feat = self.bottleneck(global_feat) # normalize for angular softmax
66 | if self.training:
67 | cls_score = self.classifier(feat)
68 | return cls_score, feat #feat or global_feat for triplet loss
69 | else:
70 | return global_feat ## feat
71 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/solver/__init__.py:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | """
3 | @author: sherlock
4 | @contact: sherlockliao01@gmail.com
5 | """
6 |
7 | from .build import make_optimizer
8 | from .lr_scheduler import WarmupMultiStepLR
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/solver/__init__.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Simon4Yan/feature_learning/23ecc1bb2ce3ce4bece9159ca4ecc420e3e8f34c/Feature_Learning/learning_model/solver/__init__.pyc
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/solver/__pycache__/__init__.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Simon4Yan/feature_learning/23ecc1bb2ce3ce4bece9159ca4ecc420e3e8f34c/Feature_Learning/learning_model/solver/__pycache__/__init__.cpython-37.pyc
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/solver/__pycache__/build.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Simon4Yan/feature_learning/23ecc1bb2ce3ce4bece9159ca4ecc420e3e8f34c/Feature_Learning/learning_model/solver/__pycache__/build.cpython-37.pyc
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/solver/__pycache__/lr_scheduler.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Simon4Yan/feature_learning/23ecc1bb2ce3ce4bece9159ca4ecc420e3e8f34c/Feature_Learning/learning_model/solver/__pycache__/lr_scheduler.cpython-37.pyc
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/solver/build.py:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | """
3 | @author: sherlock
4 | @contact: sherlockliao01@gmail.com
5 | """
6 |
7 | import torch
8 |
9 |
10 | def make_optimizer(cfg, model):
11 | params = []
12 | #ignored_params = list(map(id, model.classifier.parameters() )) + list(map(id, model.bottleneck.parameters() ))
13 | #base_params = filter(lambda p: id(p) not in ignored_params, model.parameters())
14 |
15 | for key, value in model.base.named_parameters():
16 | if not value.requires_grad:
17 | continue
18 | lr = cfg.SOLVER.BASE_LR
19 | weight_decay = cfg.SOLVER.WEIGHT_DECAY
20 | if "bias" in key:
21 | lr = cfg.SOLVER.BASE_LR * cfg.SOLVER.BIAS_LR_FACTOR
22 | weight_decay = cfg.SOLVER.WEIGHT_DECAY_BIAS
23 | params += [{"params": [value], "lr": lr, "weight_decay": weight_decay}]
24 |
25 | for key, value in model.classifier.named_parameters():
26 | if not value.requires_grad:
27 | continue
28 | lr = cfg.SOLVER.BASE_LR
29 | weight_decay = cfg.SOLVER.WEIGHT_DECAY
30 | if "bias" in key:
31 | lr = cfg.SOLVER.BASE_LR * cfg.SOLVER.BIAS_LR_FACTOR
32 | weight_decay = cfg.SOLVER.WEIGHT_DECAY_BIAS
33 | params += [{"params": [value], "lr": lr*2, "weight_decay": weight_decay}]
34 |
35 | for key, value in model.bottleneck.named_parameters():
36 | if not value.requires_grad:
37 | continue
38 | lr = cfg.SOLVER.BASE_LR
39 | weight_decay = cfg.SOLVER.WEIGHT_DECAY
40 | if "bias" in key:
41 | lr = cfg.SOLVER.BASE_LR * cfg.SOLVER.BIAS_LR_FACTOR
42 | weight_decay = cfg.SOLVER.WEIGHT_DECAY_BIAS
43 | params += [{"params": [value], "lr": lr*2, "weight_decay": weight_decay}]
44 |
45 | if cfg.SOLVER.OPTIMIZER_NAME == 'SGD':
46 | optimizer = getattr(torch.optim, cfg.SOLVER.OPTIMIZER_NAME)(params, momentum=cfg.SOLVER.MOMENTUM)
47 | else:
48 | optimizer = getattr(torch.optim, cfg.SOLVER.OPTIMIZER_NAME)(params)
49 | return optimizer
50 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/solver/build.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Simon4Yan/feature_learning/23ecc1bb2ce3ce4bece9159ca4ecc420e3e8f34c/Feature_Learning/learning_model/solver/build.pyc
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/solver/lr_scheduler.py:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | """
3 | @author: liaoxingyu
4 | @contact: sherlockliao01@gmail.com
5 | """
6 | from bisect import bisect_right
7 | import torch
8 |
9 |
10 | # FIXME ideally this would be achieved with a CombinedLRScheduler,
11 | # separating MultiStepLR with WarmupLR
12 | # but the current LRScheduler design doesn't allow it
13 |
14 | class WarmupMultiStepLR(torch.optim.lr_scheduler._LRScheduler):
15 | def __init__(
16 | self,
17 | optimizer,
18 | milestones,
19 | gamma=0.1,
20 | warmup_factor=1.0 / 3,
21 | warmup_iters=500,
22 | warmup_method="linear",
23 | last_epoch=-1,
24 | ):
25 | if not list(milestones) == sorted(milestones):
26 | raise ValueError(
27 | "Milestones should be a list of" " increasing integers. Got {}",
28 | milestones,
29 | )
30 |
31 | if warmup_method not in ("constant", "linear"):
32 | raise ValueError(
33 | "Only 'constant' or 'linear' warmup_method accepted"
34 | "got {}".format(warmup_method)
35 | )
36 | self.milestones = milestones
37 | self.gamma = gamma
38 | self.warmup_factor = warmup_factor
39 | self.warmup_iters = warmup_iters
40 | self.warmup_method = warmup_method
41 | super(WarmupMultiStepLR, self).__init__(optimizer, last_epoch)
42 |
43 | def get_lr(self):
44 | warmup_factor = 1
45 | if self.last_epoch < self.warmup_iters:
46 | if self.warmup_method == "constant":
47 | warmup_factor = self.warmup_factor
48 | elif self.warmup_method == "linear":
49 | alpha = self.last_epoch / self.warmup_iters
50 | warmup_factor = self.warmup_factor * (1 - alpha) + alpha
51 | return [
52 | base_lr
53 | * warmup_factor
54 | * self.gamma ** bisect_right(self.milestones, self.last_epoch)
55 | for base_lr in self.base_lrs
56 | ]
57 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/solver/lr_scheduler.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Simon4Yan/feature_learning/23ecc1bb2ce3ce4bece9159ca4ecc420e3e8f34c/Feature_Learning/learning_model/solver/lr_scheduler.pyc
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/tests/__init__.py:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | """
3 | @author: sherlock
4 | @contact: sherlockliao01@gmail.com
5 | """
6 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/tests/lr_scheduler_test.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import unittest
3 |
4 | import torch
5 | from torch import nn
6 |
7 | sys.path.append('.')
8 | from solver.lr_scheduler import WarmupMultiStepLR
9 | from solver.build import make_optimizer
10 | from config import cfg
11 |
12 |
13 | class MyTestCase(unittest.TestCase):
14 | def test_something(self):
15 | net = nn.Linear(10, 10)
16 | optimizer = make_optimizer(cfg, net)
17 | lr_scheduler = WarmupMultiStepLR(optimizer, [20, 40], warmup_iters=10)
18 | for i in range(50):
19 | lr_scheduler.step()
20 | for j in range(3):
21 | print(i, lr_scheduler.get_lr()[0])
22 | optimizer.step()
23 |
24 |
25 | if __name__ == '__main__':
26 | unittest.main()
27 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/tools/__init__.py:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | """
3 | @author: sherlock
4 | @contact: sherlockliao01@gmail.com
5 | """
6 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/tools/test.py:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | """
3 | @author: sherlock
4 | @contact: sherlockliao01@gmail.com
5 | """
6 |
7 | import argparse
8 | import os
9 | import sys
10 | from os import mkdir
11 |
12 | import torch
13 | from torch.backends import cudnn
14 |
15 | sys.path.append('.')
16 | from config import cfg
17 | from data import make_data_loader
18 | from engine.inference import inference
19 | from modeling import build_model
20 | from utils.logger import setup_logger
21 |
22 |
23 | def main():
24 | parser = argparse.ArgumentParser(description="ReID Baseline Inference")
25 | parser.add_argument(
26 | "--config_file", default="", help="path to config file", type=str
27 | )
28 | parser.add_argument("opts", help="Modify config options using the command-line", default=None,
29 | nargs=argparse.REMAINDER)
30 |
31 | args = parser.parse_args()
32 |
33 | num_gpus = int(os.environ["WORLD_SIZE"]) if "WORLD_SIZE" in os.environ else 1
34 |
35 | if args.config_file != "":
36 | cfg.merge_from_file(args.config_file)
37 | cfg.merge_from_list(args.opts)
38 | cfg.freeze()
39 |
40 | output_dir = cfg.OUTPUT_DIR
41 | if output_dir and not os.path.exists(output_dir):
42 | mkdir(output_dir)
43 |
44 | logger = setup_logger("reid_baseline", output_dir, 0)
45 | logger.info("Using {} GPUS".format(num_gpus))
46 | logger.info(args)
47 |
48 | if args.config_file != "":
49 | logger.info("Loaded configuration file {}".format(args.config_file))
50 | with open(args.config_file, 'r') as cf:
51 | config_str = "\n" + cf.read()
52 | logger.info(config_str)
53 | logger.info("Running with config:\n{}".format(cfg))
54 |
55 | cudnn.benchmark = True
56 |
57 | train_loader, val_loader, num_query, num_classes = make_data_loader(cfg)
58 | model = build_model(cfg, num_classes)
59 | model.load_state_dict(torch.load(cfg.TEST.WEIGHT))
60 |
61 | inference(cfg, model, val_loader, num_query)
62 |
63 |
64 | if __name__ == '__main__':
65 | main()
66 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/tools/train.py:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | """
3 | @author: sherlock
4 | @contact: sherlockliao01@gmail.com
5 | """
6 |
7 | import argparse
8 | import os
9 | import sys
10 | import torch.nn as nn
11 |
12 | from torch.backends import cudnn
13 |
14 | sys.path.append('.')
15 | from config import cfg
16 | from data import make_data_loader
17 | from engine.trainer import do_train
18 | from modeling import build_model
19 | from layers import make_loss
20 | from solver import make_optimizer, WarmupMultiStepLR
21 |
22 | from utils.logger import setup_logger
23 |
24 |
25 | def train(cfg):
26 | # prepare dataset
27 | train_loader, val_loader, num_query, num_classes = make_data_loader(cfg)
28 | # prepare model
29 | model = build_model(cfg, num_classes)
30 |
31 | optimizer = make_optimizer(cfg, model)
32 | scheduler = WarmupMultiStepLR(optimizer, cfg.SOLVER.STEPS, cfg.SOLVER.GAMMA, cfg.SOLVER.WARMUP_FACTOR,
33 | cfg.SOLVER.WARMUP_ITERS, cfg.SOLVER.WARMUP_METHOD)
34 |
35 | ## multi-gpu
36 | #model = nn.DataParallel(model, device_ids=[0,1])
37 |
38 | loss_func = make_loss(cfg)
39 |
40 | arguments = {}
41 |
42 | do_train(
43 | cfg,
44 | model,
45 | train_loader,
46 | val_loader,
47 | optimizer,
48 | scheduler,
49 | loss_func,
50 | num_query
51 | )
52 |
53 |
54 | def main():
55 | parser = argparse.ArgumentParser(description="ReID Baseline Training")
56 | parser.add_argument(
57 | "--config_file", default="", help="path to config file", type=str
58 | )
59 | parser.add_argument("opts", help="Modify config options using the command-line", default=None,
60 | nargs=argparse.REMAINDER)
61 |
62 | args = parser.parse_args()
63 |
64 | num_gpus = int(os.environ["WORLD_SIZE"]) if "WORLD_SIZE" in os.environ else 1
65 |
66 | if args.config_file != "":
67 | cfg.merge_from_file(args.config_file)
68 | cfg.merge_from_list(args.opts)
69 | cfg.freeze()
70 |
71 | output_dir = cfg.OUTPUT_DIR
72 | if output_dir and not os.path.exists(output_dir):
73 | os.makedirs(output_dir)
74 |
75 | logger = setup_logger("reid_baseline", output_dir, 0)
76 | logger.info("Using {} GPUS".format(num_gpus))
77 | logger.info(args)
78 |
79 | if args.config_file != "":
80 | logger.info("Loaded configuration file {}".format(args.config_file))
81 | with open(args.config_file, 'r') as cf:
82 | config_str = "\n" + cf.read()
83 | logger.info(config_str)
84 | logger.info("Running with config:\n{}".format(cfg))
85 |
86 | cudnn.benchmark = True
87 | train(cfg)
88 |
89 |
90 | if __name__ == '__main__':
91 | main()
92 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/tools/update.py:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | """
3 | @author: weijian
4 | @contact: dengwj16@gmail.com
5 | """
6 |
7 | import argparse
8 | import os
9 | import sys
10 | from os import mkdir
11 |
12 | import torch
13 | from torch.backends import cudnn
14 |
15 | sys.path.append('.')
16 | from config import cfg
17 | from data import make_data_loader
18 | from engine.inference import inference
19 | from modeling import build_model
20 | from utils.logger import setup_logger
21 | from data.datasets.eval_reid import eval_func
22 | import logging
23 | import numpy as np
24 |
25 | from utils.re_ranking import re_ranking
26 |
27 | def fliplr(img):
28 | '''flip horizontal'''
29 | inv_idx = torch.arange(img.size(3)-1,-1,-1).long() # N x C x H x W
30 | img_flip = img.index_select(3,inv_idx)
31 | return img_flip
32 |
33 | def get_id(img_path):
34 | camera_id = []
35 | labels = []
36 | for path, v in img_path:
37 | filename = os.path.basename(path)
38 | label = filename[0:4]
39 | camera = filename.split('c')[1]
40 | if label[0:2]=='-1':
41 | labels.append(-1)
42 | else:
43 | labels.append(int(label))
44 | camera_id.append(int(camera[0]))
45 | return camera_id, labels
46 |
47 | def extract_feature(model, dataloaders, num_query):
48 | features = []
49 | count = 0
50 | img_path = []
51 |
52 | for data in dataloaders:
53 | img, _, _ = data
54 | n, c, h, w = img.size()
55 | count += n
56 | ff = torch.FloatTensor(n, 1024).zero_().cuda() # 2048 is pool5 of resnet
57 | for i in range(2):
58 | if(i==1):
59 | img = fliplr(img)
60 | input_img = img.cuda()
61 | outputs = model(input_img)
62 | f = outputs.float()
63 | ff = ff+f
64 | # norm feature
65 | fnorm = torch.norm(ff, p=2, dim=1, keepdim=True)
66 | ff = ff.div(fnorm.expand_as(ff))
67 | features.append(ff)
68 | features = torch.cat(features, 0)
69 |
70 | # query
71 | qf = features[:num_query]
72 | # gallery
73 | gf = features[num_query:]
74 | return qf, gf
75 |
76 | def main():
77 | parser = argparse.ArgumentParser(description="ReID Baseline Inference")
78 | parser.add_argument(
79 | "--config_file", default="", help="path to config file", type=str
80 | )
81 | parser.add_argument("opts", help="Modify config options using the command-line", default=None,
82 | nargs=argparse.REMAINDER)
83 |
84 | args = parser.parse_args()
85 |
86 | num_gpus = int(os.environ["WORLD_SIZE"]) if "WORLD_SIZE" in os.environ else 1
87 |
88 | if args.config_file != "":
89 | cfg.merge_from_file(args.config_file)
90 | cfg.merge_from_list(args.opts)
91 | cfg.freeze()
92 |
93 | output_dir = cfg.OUTPUT_DIR
94 | if output_dir and not os.path.exists(output_dir):
95 | mkdir(output_dir)
96 |
97 | logger = setup_logger("reid_baseline", output_dir, 0)
98 | logger.info("Using {} GPUS".format(num_gpus))
99 | logger.info(args)
100 |
101 | if args.config_file != "":
102 | logger.info("Loaded configuration file {}".format(args.config_file))
103 | with open(args.config_file, 'r') as cf:
104 | config_str = "\n" + cf.read()
105 | logger.info(config_str)
106 | logger.info("Running with config:\n{}".format(cfg))
107 |
108 | cudnn.benchmark = True
109 |
110 | train_loader, val_loader, num_query, num_classes = make_data_loader(cfg)
111 | model = build_model(cfg, num_classes)
112 | model.load_state_dict(torch.load(cfg.TEST.WEIGHT))
113 | model = model.cuda()
114 | model = model.eval()
115 |
116 | logger = logging.getLogger("reid_baseline.inference")
117 | logger.info("Start inferencing")
118 | with torch.no_grad():
119 | qf, gf = extract_feature(model, val_loader, num_query)
120 |
121 | # save feature
122 | np.save('../data/feature_expansion/' + cfg.TEST.QF_NAME, qf.cpu().numpy())
123 | np.save('../data/feature_expansion/' + cfg.TEST.GF_NAME, gf.cpu().numpy())
124 |
125 | '''
126 | q_g_dist = np.dot(qf.cpu().numpy(), np.transpose(gf.cpu().numpy()))
127 | q_q_dist = np.dot(qf.cpu().numpy(), np.transpose(qf.cpu().numpy()))
128 | g_g_dist = np.dot(gf.cpu().numpy(), np.transpose(gf.cpu().numpy()))
129 |
130 | re_rank_dist = re_ranking(q_g_dist, q_q_dist, g_g_dist)
131 | '''
132 |
133 | if __name__ == '__main__':
134 | main()
135 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/utils/__init__.py:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | """
3 | @author: sherlock
4 | @contact: sherlockliao01@gmail.com
5 | """
6 |
7 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/utils/__pycache__/__init__.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Simon4Yan/feature_learning/23ecc1bb2ce3ce4bece9159ca4ecc420e3e8f34c/Feature_Learning/learning_model/utils/__pycache__/__init__.cpython-37.pyc
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/utils/__pycache__/iotools.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Simon4Yan/feature_learning/23ecc1bb2ce3ce4bece9159ca4ecc420e3e8f34c/Feature_Learning/learning_model/utils/__pycache__/iotools.cpython-37.pyc
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/utils/__pycache__/logger.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Simon4Yan/feature_learning/23ecc1bb2ce3ce4bece9159ca4ecc420e3e8f34c/Feature_Learning/learning_model/utils/__pycache__/logger.cpython-37.pyc
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/utils/__pycache__/model_loder.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Simon4Yan/feature_learning/23ecc1bb2ce3ce4bece9159ca4ecc420e3e8f34c/Feature_Learning/learning_model/utils/__pycache__/model_loder.cpython-37.pyc
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/utils/__pycache__/re_ranking.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Simon4Yan/feature_learning/23ecc1bb2ce3ce4bece9159ca4ecc420e3e8f34c/Feature_Learning/learning_model/utils/__pycache__/re_ranking.cpython-37.pyc
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/utils/__pycache__/reid_metric.cpython-37.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Simon4Yan/feature_learning/23ecc1bb2ce3ce4bece9159ca4ecc420e3e8f34c/Feature_Learning/learning_model/utils/__pycache__/reid_metric.cpython-37.pyc
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/utils/iotools.py:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | """
3 | @author: sherlock
4 | @contact: sherlockliao01@gmail.com
5 | """
6 |
7 | import errno
8 | import json
9 | import os
10 |
11 | import os.path as osp
12 |
13 |
14 | def mkdir_if_missing(directory):
15 | if not osp.exists(directory):
16 | try:
17 | os.makedirs(directory)
18 | except OSError as e:
19 | if e.errno != errno.EEXIST:
20 | raise
21 |
22 |
23 | def check_isfile(path):
24 | isfile = osp.isfile(path)
25 | if not isfile:
26 | print("=> Warning: no file found at '{}' (ignored)".format(path))
27 | return isfile
28 |
29 |
30 | def read_json(fpath):
31 | with open(fpath, 'r') as f:
32 | obj = json.load(f)
33 | return obj
34 |
35 |
36 | def write_json(obj, fpath):
37 | mkdir_if_missing(osp.dirname(fpath))
38 | with open(fpath, 'w') as f:
39 | json.dump(obj, f, indent=4, separators=(',', ': '))
40 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/utils/logger.py:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | """
3 | @author: sherlock
4 | @contact: sherlockliao01@gmail.com
5 | """
6 |
7 | import logging
8 | import os
9 | import sys
10 |
11 |
12 | def setup_logger(name, save_dir, distributed_rank):
13 | logger = logging.getLogger(name)
14 | logger.setLevel(logging.DEBUG)
15 | # don't log results for the non-master process
16 | if distributed_rank > 0:
17 | return logger
18 | ch = logging.StreamHandler(stream=sys.stdout)
19 | ch.setLevel(logging.DEBUG)
20 | formatter = logging.Formatter("%(asctime)s %(name)s %(levelname)s: %(message)s")
21 | ch.setFormatter(formatter)
22 | logger.addHandler(ch)
23 |
24 | if save_dir:
25 | fh = logging.FileHandler(os.path.join(save_dir, "log.txt"), mode='w')
26 | fh.setLevel(logging.DEBUG)
27 | fh.setFormatter(formatter)
28 | logger.addHandler(fh)
29 |
30 | return logger
31 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/utils/model_loder.py:
--------------------------------------------------------------------------------
1 | from torch import nn
2 | import torch
3 | import os.path as osp
4 |
5 |
6 | def load_checkpoint(fpath):
7 | if osp.isfile(fpath):
8 | checkpoint = torch.load(fpath)
9 | print("=> Loaded checkpoint '{}'".format(fpath))
10 | return checkpoint
11 | else:
12 | raise ValueError("=> No checkpoint found at '{}'".format(fpath))
13 |
14 | def checkpoint_loader(model, path, eval_only=False):
15 | checkpoint = load_checkpoint(path)
16 | pretrained_dict = checkpoint['state_dict']
17 | if isinstance(model, nn.DataParallel):
18 | Parallel = 1
19 | model = model.module.cpu()
20 | else:
21 | Parallel = 0
22 |
23 | model_dict = model.state_dict()
24 | # 1. filter out unnecessary keys
25 | pretrained_dict = {k: v for k, v in pretrained_dict.items() if k in model_dict}
26 | if eval_only:
27 | keys_to_del = []
28 | for key in pretrained_dict.keys():
29 | if 'classifier' in key:
30 | keys_to_del.append(key)
31 | for key in keys_to_del:
32 | del pretrained_dict[key]
33 | pass
34 | # 2. overwrite entries in the existing state dict
35 | model_dict.update(pretrained_dict)
36 | # 3. load the new state dict
37 | model.load_state_dict(model_dict)
38 |
39 | start_epoch = checkpoint['epoch']
40 | best_top1 = checkpoint['best_top1']
41 |
42 | if Parallel:
43 | model = nn.DataParallel(model).cuda()
44 |
45 | return model, start_epoch, best_top1
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/utils/re_ranking.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python2/python3
2 | # -*- coding: utf-8 -*-
3 | """
4 | Created on Mon Jun 26 14:46:56 2017
5 | @author: luohao
6 | Modified by Houjing Huang, 2017-12-22.
7 | - This version accepts distance matrix instead of raw features.
8 | - The difference of `/` division between python 2 and 3 is handled.
9 | - numpy.float16 is replaced by numpy.float32 for numerical precision.
10 |
11 | Modified by Zhedong Zheng, 2018-1-12.
12 | - replace sort with topK, which save about 30s.
13 | """
14 |
15 | """
16 | CVPR2017 paper:Zhong Z, Zheng L, Cao D, et al. Re-ranking Person Re-identification with k-reciprocal Encoding[J]. 2017.
17 | url:http://openaccess.thecvf.com/content_cvpr_2017/papers/Zhong_Re-Ranking_Person_Re-Identification_CVPR_2017_paper.pdf
18 | Matlab version: https://github.com/zhunzhong07/person-re-ranking
19 | """
20 |
21 | """
22 | API
23 | q_g_dist: query-gallery distance matrix, numpy array, shape [num_query, num_gallery]
24 | q_q_dist: query-query distance matrix, numpy array, shape [num_query, num_query]
25 | g_g_dist: gallery-gallery distance matrix, numpy array, shape [num_gallery, num_gallery]
26 | k1, k2, lambda_value: parameters, the original paper is (k1=20, k2=6, lambda_value=0.3)
27 | Returns:
28 | final_dist: re-ranked distance, numpy array, shape [num_query, num_gallery]
29 | """
30 |
31 |
32 | import numpy as np
33 |
34 | def k_reciprocal_neigh( initial_rank, i, k1):
35 | forward_k_neigh_index = initial_rank[i,:k1+1]
36 | backward_k_neigh_index = initial_rank[forward_k_neigh_index,:k1+1]
37 | fi = np.where(backward_k_neigh_index==i)[0]
38 | return forward_k_neigh_index[fi]
39 |
40 | def re_ranking(q_g_dist, q_q_dist, g_g_dist, k1=20, k2=6, lambda_value=0.3):
41 | # The following naming, e.g. gallery_num, is different from outer scope.
42 | # Don't care about it.
43 | original_dist = np.concatenate(
44 | [np.concatenate([q_q_dist, q_g_dist], axis=1),
45 | np.concatenate([q_g_dist.T, g_g_dist], axis=1)],
46 | axis=0)
47 | original_dist = 2. - 2 * original_dist # change the cosine similarity metric to euclidean similarity metric
48 | original_dist = np.power(original_dist, 2).astype(np.float32)
49 | original_dist = np.transpose(1. * original_dist/np.max(original_dist,axis = 0))
50 | V = np.zeros_like(original_dist).astype(np.float32)
51 | #initial_rank = np.argsort(original_dist).astype(np.int32)
52 | # top K1+1
53 | initial_rank = np.argpartition( original_dist, range(1,k1+1) )
54 |
55 | query_num = q_g_dist.shape[0]
56 | all_num = original_dist.shape[0]
57 |
58 | for i in range(all_num):
59 | # k-reciprocal neighbors
60 | k_reciprocal_index = k_reciprocal_neigh( initial_rank, i, k1)
61 | k_reciprocal_expansion_index = k_reciprocal_index
62 | for j in range(len(k_reciprocal_index)):
63 | candidate = k_reciprocal_index[j]
64 | candidate_k_reciprocal_index = k_reciprocal_neigh( initial_rank, candidate, int(np.around(k1/2)))
65 | if len(np.intersect1d(candidate_k_reciprocal_index,k_reciprocal_index))> 2./3*len(candidate_k_reciprocal_index):
66 | k_reciprocal_expansion_index = np.append(k_reciprocal_expansion_index,candidate_k_reciprocal_index)
67 |
68 | k_reciprocal_expansion_index = np.unique(k_reciprocal_expansion_index)
69 | weight = np.exp(-original_dist[i,k_reciprocal_expansion_index])
70 | V[i,k_reciprocal_expansion_index] = 1.*weight/np.sum(weight)
71 |
72 | original_dist = original_dist[:query_num,]
73 | if k2 != 1:
74 | V_qe = np.zeros_like(V,dtype=np.float32)
75 | for i in range(all_num):
76 | V_qe[i,:] = np.mean(V[initial_rank[i,:k2],:],axis=0)
77 | V = V_qe
78 | del V_qe
79 | del initial_rank
80 | invIndex = []
81 | for i in range(all_num):
82 | invIndex.append(np.where(V[:,i] != 0)[0])
83 |
84 | jaccard_dist = np.zeros_like(original_dist,dtype = np.float32)
85 |
86 | for i in range(query_num):
87 | temp_min = np.zeros(shape=[1,all_num],dtype=np.float32)
88 | indNonZero = np.where(V[i,:] != 0)[0]
89 | indImages = []
90 | indImages = [invIndex[ind] for ind in indNonZero]
91 | for j in range(len(indNonZero)):
92 | temp_min[0,indImages[j]] = temp_min[0,indImages[j]]+ np.minimum(V[i,indNonZero[j]],V[indImages[j],indNonZero[j]])
93 | jaccard_dist[i] = 1-temp_min/(2.-temp_min)
94 |
95 | final_dist = jaccard_dist*(1-lambda_value) + original_dist*lambda_value
96 | del original_dist
97 | del V
98 | del jaccard_dist
99 | final_dist = final_dist[:query_num,query_num:]
100 | return final_dist
101 |
--------------------------------------------------------------------------------
/Feature_Learning/learning_model/utils/reid_metric.py:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | """
3 | @author: liaoxingyu
4 | @contact: sherlockliao01@gmail.com
5 | """
6 |
7 | import numpy as np
8 | import torch
9 | from ignite.metrics import Metric
10 |
11 | from data.datasets.eval_reid import eval_func
12 | from data.datasets.ranking import cmc
13 | from data.datasets.ranking import mean_ap
14 | import scipy.io
15 |
16 | class R1_mAP(Metric):
17 | def __init__(self, num_query, max_rank=50):
18 | super(R1_mAP, self).__init__()
19 | self.num_query = num_query
20 | self.max_rank = max_rank
21 |
22 | def reset(self):
23 | self.feats = []
24 | self.pids = []
25 | self.camids = []
26 |
27 | def update(self, output):
28 | feat, pid, camid = output
29 | self.feats.append(feat)
30 | self.pids.extend(np.asarray(pid))
31 | self.camids.extend(np.asarray(camid))
32 |
33 | def compute(self):
34 | feats = torch.cat(self.feats, dim=0)
35 | # query
36 | qf = feats[:self.num_query]
37 | q_pids = np.asarray(self.pids[:self.num_query])
38 | q_camids = np.asarray(self.camids[:self.num_query])
39 | # gallery
40 | gf = feats[self.num_query:]
41 | g_pids = np.asarray(self.pids[self.num_query:])
42 | g_camids = np.asarray(self.camids[self.num_query:])
43 | m, n = qf.shape[0], gf.shape[0]
44 | distmat = torch.pow(qf, 2).sum(dim=1, keepdim=True).expand(m, n) + \
45 | torch.pow(gf, 2).sum(dim=1, keepdim=True).expand(n, m).t()
46 | distmat.addmm_(1, -2, qf, gf.t())
47 | distmat = distmat.cpu().numpy()
48 | #dis_save = {'dis': distmat}
49 | #scipy.io.savemat('distmat_ori.mat', dis_save)
50 | cmc1, mAP = eval_func(distmat, q_pids, g_pids, q_camids, g_camids)
51 | #cmc0 = cmc(distmat, q_pids, g_pids, q_camids, g_camids)
52 | #mAP = mean_ap(distmat, q_pids, g_pids, q_camids, g_camids)
53 | return cmc1, mAP
54 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Simon4Yan
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Vehicle ReID_baseline
2 | Baseline model (with bottleneck) for vehicle ReID (using softmax and triplet loss).
3 |
4 | ## Feature_Learning
5 | This part is for learning feature extractor. The code is modified form [reid_baseline](https://github.com/L1aoXingyu/reid_baseline), you can check each folder's purpose by yourself.
6 |
7 | ### REFERENCE
8 | Lv, K., Deng, W., Hou, Y., Du, H., Sheng, H., Jiao, J., & Zheng, L. (2019). Vehicle reidentification with the location and time stamp. In Proc. CVPR Workshops.
9 | ```
10 | @inproceedings{lv2019vehicle,
11 | title={Vehicle reidentification with the location and time stamp},
12 | author={Lv, Kai and Deng, Weijian and Hou, Yunzhong and Du, Heming and Sheng, Hao and Jiao, Jianbin and Zheng, Liang},
13 | booktitle={Proc. CVPR Workshops},
14 | year={2019}
15 | }
16 | ```
17 | #### If you have any question, please contact us by E-mail (dengwj16@gmail.com) or open an issue in this project. Thanks.
18 |
--------------------------------------------------------------------------------