From 457103137753866933da8d4a084da0101476f5d9 Mon Sep 17 00:00:00 2001 From: HydrogenSulfate <490868991@qq.com> Date: Thu, 2 Jun 2022 13:12:13 +0800 Subject: [PATCH 1/9] add reid docs and images --- docs/en/algorithm_introduction/reid.md | 206 ++++++++++++++++++++++ docs/images/reid/strong-baseline.jpg | Bin 0 -> 271341 bytes docs/zh_CN/algorithm_introduction/reid.md | 206 ++++++++++++++++++++++ 3 files changed, 412 insertions(+) create mode 100644 docs/en/algorithm_introduction/reid.md create mode 100644 docs/images/reid/strong-baseline.jpg create mode 100644 docs/zh_CN/algorithm_introduction/reid.md diff --git a/docs/en/algorithm_introduction/reid.md b/docs/en/algorithm_introduction/reid.md new file mode 100644 index 000000000..82b8ad4e6 --- /dev/null +++ b/docs/en/algorithm_introduction/reid.md @@ -0,0 +1,206 @@ +English|[Simplified Chinese](../../zh_CN/algorithm_introduction/reid.md) +# ReID pedestrian re-identification + +### 1. Introduction to algorithms/application scenarios + +Pedestrian re-identification (Person re-identification), also known as pedestrian re-identification, is the use of [computer vision](https://baike.baidu.com/item/computer vision/2803351) technology to judge [image](https://baike .baidu.com/item/image/773234) or whether there is a [technique] of a particular pedestrian in the video sequence (https://baike.baidu.com/item/technique/13014499). Widely regarded as a sub-problem of [Image Retrieval](https://baike.baidu.com/item/image_retrieval/1150910). Given a surveillance pedestrian image, retrieve the pedestrian image across devices. It aims to make up for the visual limitations of fixed cameras, and can be combined with [pedestrian detection](https://baike.baidu.com/item/pedestrian detection/20590256)/pedestrian tracking technology, which can be widely used in [intelligent video surveillance] ](https://baike.baidu.com/item/intelligent video surveillance/10717227), intelligent security and other fields. + +### 2. Introduction to ReID strong-baseline algorithm + +In the past person re-identification methods, the feature extraction module is used to extract the global or multi-granularity features of the image, and then a high-dimensional feature vector is obtained through the fusion module. Use the classification head to map the feature vector into the probability of each category during training to optimize the entire model in the way of classification tasks; directly use the high-dimensional feature vector as an image descriptor in the retrieval library during testing or inference. search to get the search results. The ReID strong-baseline algorithm proposes several methods to effectively optimize training and retrieval to improve the overall model performance. + +#### 2.1 Principle of ReID strong-baseline algorithm + +Paper source: [Bag of Tricks and A Strong Baseline for Deep Person Re-identification](https://openaccess.thecvf.com/content_CVPRW_2019/papers/TRMTMCT/Luo_Bag_of_Tricks_and_a_Strong_Baseline_for_Deep_Person_CVPRW_2019_paper.pdf) + + + +Principle introduction: The author mainly uses the following optimization methods + +1. Warmup, let the learning rate gradually increase at the beginning of training and then start to decrease, which is conducive to finding better parameters during gradient descent. +2. Random erasing augmentation, random area erasing, enhances the generalization of the model. +3. Label smoothing, label smoothing, enhance the generalization of the model. +4. Last stride=1, cancel the downsampling of the last stage of the feature extraction module, increase the resolution of the output feature map to retain more details and enhance the classification ability of the model. +5. BNNeck, before the feature vector is input into the classification head, it goes through BNNeck, so that the feature vector becomes a normal distribution, which reduces the difficulty of optimizing ID Loss and TripLetLoss at the same time. +6. Center loss, give each category a learnable cluster center feature, and make the intra-class features close to the cluster center during training to reduce intra-class differences and increase inter-class differences. +7. Reranking, consider whether the neighboring candidate objects of the retrieved image also contain retrieval targets during retrieval, so as to optimize the distance matrix and finally improve the retrieval accuracy. + +#### 2.2a Quick start + +The quick start chapter mainly takes the `softmax_triplet_with_center.yaml` configuration and trained model file as an example to test on the Market1501 dataset. + +1. Download the [Market-1501-v15.09.15.zip](https://pan.baidu.com/s/1ntIi2Op?_at_=1654142245770) dataset, extract it to `PaddleClas/dataset/`, and organize it as follows File structure: + + ```shell + PaddleClas/dataset/market1501 + └── Market-1501-v15.09.15/ + ├── bounding_box_test/ + ├── bounding_box_train/ + ├── gt_bbox/ + ├── gt_query/ + ├── query/ + ├── generate_anno.py + ├── bounding_box_test.txt + ├── bounding_box_train.txt + ├── query.txt + └── readme.txt + ``` + +2. Download [reid_strong_baseline_softmax_with_center.epoch_120.pdparams](reid_strong_baseline_softmax_with_center.epoch_120.pdparams) to `PaddleClas/pretrained_models` folder + + ```shell + cd PaddleClas + mkdir pretrained_models + cd pretrained_models + wget https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/reid_strong_baseline_softmax_with_center.epoch_120.pdparams + cd.. + ``` + +3. Use the downloaded `softmax_triplet_with_center.pdparams` to test on the Market1501 dataset + + ```shell + python3.7 tools/eval.py \ + -c ppcls/configs/reid/strong_baseline/baseline.yaml \ + -o Global.pretrained_model="pretrained_models/reid_strong_baseline_softmax_with_center.epoch_120" + ``` + +4. View the output result + + ```log + ... + [2022/06/02 03:08:07] ppcls INFO: gallery feature calculation process: [0/125] + [2022/06/02 03:08:11] ppcls INFO: gallery feature calculation process: [20/125] + [2022/06/02 03:08:15] ppcls INFO: gallery feature calculation process: [40/125] + [2022/06/02 03:08:19] ppcls INFO: gallery feature calculation process: [60/125] + [2022/06/02 03:08:23] ppcls INFO: gallery feature calculation process: [80/125] + [2022/06/02 03:08:27] ppcls INFO: gallery feature calculation process: [100/125] + [2022/06/02 03:08:31] ppcls INFO: gallery feature calculation process: [120/125] + [2022/06/02 03:08:32] ppcls INFO: Build gallery done, all feat shape: [15913, 2048], begin to eval.. + [2022/06/02 03:08:33] ppcls INFO: query feature calculation process: [0/27] + [2022/06/02 03:08:36] ppcls INFO: query feature calculation process: [20/27] + [2022/06/02 03:08:38] ppcls INFO: Build query done, all feat shape: [3368, 2048], begin to eval.. + [2022/06/02 03:08:38] ppcls INFO: re_ranking=False + [2022/06/02 03:08:39] ppcls INFO: [Eval][Epoch 0][Avg]recall1: 0.94270, recall5: 0.98189, mAP: 0.85799 + ``` + + It can be seen that the metrics of the `reid_strong_baseline_softmax_with_center.epoch_120.pdparams` model provided by us on the Market1501 dataset are recall@1=0.94270, recall@5=0.98189, mAP=0.85799 + +#### 2.2b Model training/testing/inference + +- Model training + + 1. Download the [Market-1501-v15.09.15.zip](https://pan.baidu.com/s/1ntIi2Op?_at_=1654142245770) dataset, extract it to `PaddleClas/dataset/`, and organize it as follows File structure: + + ```shell + PaddleClas/dataset/market1501 + └── Market-1501-v15.09.15/ + ├── bounding_box_test/ + ├── bounding_box_train/ + ├── gt_bbox/ + ├── gt_query/ + ├── query/ + ├── generate_anno.py + ├── bounding_box_test.txt + ├── bounding_box_train.txt + ├── query.txt + └── readme.txt + ``` + + 2. Execute the following command to start training + + ```shell + python3.7 tools/train.py -c ./ppcls/configs/reid/strong_baseline/softmax_triplet_with_center.yaml + ``` + + Note: Single card training takes about 1 hour. + +- Model testing + + Assuming that the path of the model file to be tested is `./output/RecModel/latest.pdparams` , execute the following command to test + + ```shell + python3.7 tools/eval.py \ + -c ./ppcls/configs/reid/strong_baseline/softmax_triplet_with_center.yaml \ + -o Global.pretrained_model="./output/RecModel/latest" + ``` + + Note: The address filled after `pretrained_model` does not need to be suffixed with `.pdparams`, it will be added automatically when the program is running. + +- Model inference + + 1. DownloadInference model and extract: [reid_srong_baseline_softmax_with_center.tar](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/reid_srong_baseline_softmax_with_center.tar) + + ```shell + cd PaddleClas/deploy + wget https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/reid_srong_baseline_softmax_with_center.tar + tar xf reid_srong_baseline_softmax_with_center.tar + ``` + + 2. Modify `PaddleClas/deploy/configs/inference_rec.yaml`. Change the field after `infer_imgs:` to any image in the query folder in Market1501; change the field after `rec_inference_model_dir:` to the path of the extracted reid_srong_baseline_softmax_with_center folder; change the preprocessing configuration under the `transform_ops` field Changed to preprocessing configuration under `Eval.Query.dataset` in `softmax_triplet_with_center.yaml`. As follows + + ```yaml + Global: + infer_imgs: "../dataset/market1501/Market-1501-v15.09.15/query/0294_c1s1_066631_00.jpg" + rec_inference_model_dir: "./reid_srong_baseline_softmax_with_center" + batch_size: 1 + use_gpu: False + enable_mkldnn: True + cpu_num_threads: 10 + enable_benchmark: True + use_fp16: False + ir_optim: True + use_tensorrt: False + gpu_mem: 8000 + enable_profile: False + + RecPreProcess: + transform_ops: + -ResizeImage: + size: [128, 256] + return_numpy: False + interpolation: 'bilinear' + backend: "pil" + - ToTensor: + - Normalize: + mean: [0.485, 0.456, 0.406] + std: [0.229, 0.224, 0.225] + + RecPostProcess: null + ``` + + 3. Execute the inference command + + ```shell + python3.7 python/predict_rec.py -c ./configs/inference_rec.yaml + ``` + + 4. Check the output result. The actual result is a vector of length 2048, which represents the feature vector obtained after the input image is transformed by the model. + + ```shell + 0294_c1s1_066631_00.jpg: [ 0.01806974 0.00476423 -0.00508293 ... 0.03925538 0.00377574 + -0.00849029] + ``` + +### 3. Summary + +#### 3.1 Method summary, comparison, etc. + +The following table summarizes the accuracy metrics of the 3 configurations of ReID strong-baseline we provide on the Market1501 dataset, + +| Profile | recall@1 | mAP | Reference recall@1 | Reference mAP | +| ------------------------ | -------- | ----- | ------------ | ------- | +| baseline.yaml | 88.21 | 74.12 | 87.7 | 74.0 | +| softmax.yaml | 94.18 | 85.76 | 94.1 | 85.7 | +| softmax_with_center.yaml | 94.19 | 85.80 | 94.1 | 85.7 | + +Note: The above reference indicators are obtained by using the author's open source code to train on our equipment for many times. Due to different system environments, torch versions, and CUDA versions, there may be slight differences with the indicators provided by the author. + +#### 3.2 Usage advice/FAQ + +The Market1501 dataset is relatively small, so you can try to train multiple times to get the highest accuracy. + +#### 4 References + +1. [Bag of Tricks and A Strong Baseline for Deep Person Re-identification](https://openaccess.thecvf.com/content_CVPRW_2019/papers/TRMTMCT/Luo_Bag_of_Tricks_and_a_Strong_Baseline_for_Deep_Person_CVPRW_2019_paper.pdf) +2. [michuanhaohao/reid-strong-baseline: Bag of Tricks and A Strong Baseline for Deep Person Re-identification (github.com)](https://github.com/michuanhaohao/reid-strong-baseline) +3. [Pedestrian Re-ID dataset Market1501 dataset _star_function blog-CSDN blog _market1501 dataset](https://blog.csdn.net/qq_39220334/article/details/121470106) diff --git a/docs/images/reid/strong-baseline.jpg b/docs/images/reid/strong-baseline.jpg new file mode 100644 index 0000000000000000000000000000000000000000..26b0b1aa34b5157efbd2e6bb30371c7581ac897a GIT binary patch literal 271341 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Ðx{eP-p>_evl_39k$f5Rnu>2 zc*>$t(8_1&eTe;)G`=%L>8#6?Z4sO1a`ggD5hbRQQVzIpQ9T@XqIw{61tzYLbHN99 zf_Tt>EAJ;e+or5XoFcB`XTB9PwTXZLLerSbn4oFtZ^fIB>l~>xp+%@t*p2e6k_OMPXTo-xb+p+j4l-l#`>8jM?pOcE zIzy8O*}_7W0ybKoLe?$-FM@g4%prq|x7~X4J`$*7K%3GygDh(ga}&(%>G%*l37?5oyT#*IG-WoW>*YDtvdLd`cr(QHU7Q{Tqh;%NWsb3=iTCDC`$fLJ3oRj@hk$B(5|p~c1}hH{ zMpiEpd5L*iE7N{F9+K`^0*u*^;pUfAZWOAzs!0?0nqU`)$~O{c%09n)*+;Q#QcEsQ zmV&(3iN;y;G>FRItg<`v#hI-O8zD%L7?96?+0ntra8sDE9)#)103kx2B$YO+d;oDO z3%@;Z5rsdC#K}8uuCoM7iM!M z5f&(T;wnzhlfuY=+T!-Hc_Xyf@v&l&d?rCIx$d#_PMii#9u+YpS{4%m8uQsB8+gPx7%r|ANi^IvU>Nj5S@^Gu6xR`iIh}D zIO`WLr)GZyr$2j4k8EJV(-aYnhYAl-svnb)b^suuPlUA@V2E1)Q<0uEMAPm_2Q))52QZCjc><3bbPXdw3CJZfWjpN>UE`lOD zb1s0Z`zaN5$cpd_sasMqDhVZbf!uZqEDu+Kxc!%ZQru0)kDrSXuAd-#AfVD4;UTx; zl{Y4?(c;P9ckU%SIiI=u1Lu>2Jx-?V(yN-LHl!5tl=`X}s-airTCd|g-+Z_1l5O?2 z8eDRGRf~OF&##Ro|11N$Yp8^`%l+e*j^S8PZJC}mbH7R6uT|5Ix z#`eAm$WXD9Q_jL@)95~}=!r_!RHxU-&W~75*un6BRNs*}nf{WJ=dOwP-nv6VUr;M) z9@;>zri6XD1`D*>QXE}=hDK7&_VzxsODyGIdU*2e$4?7KooY|2=SB-m&)+Zd;ApU` zPU^7fw@ey{X$KOP`TFmc#=ny5?N2sMZ3$MDe#VbXPx4X^H{Nx&SjqZmL9$LSf5>pZ zD%WtaC?h$?Yk|GMuX_oe@SK`cPgtTmnOf}*36z{9&NS({F{ziu)+rK|_MhGg6XPoR zoK~rf!-->bf%f?y1U#BVGEub`{l!#8nVKxAsd)FsEvcM-rlwZUG+wR1aFor4^HboN zQAHi{6YNUI%yrI8&&r0gJ=QR~b)@qo^Nm{S`$uD~=WmJ1xcR!jI)RUhxF2r+-f1d3 zZ{Gz3wb)6)(E9|W2|<3QN_VsZI3;YLOs+dU=%QDSyi;}098kc2-_-u;^I_IMGPQRsur&aSDQ!k zi%``~pPJARU#xr1UOFDo-+#hbPI~=SeFmI-*3i04wD*x^bXecCl1L-@Mk|^5;e8yJ zMD9kcuR4j`GvA+5#2{~J@~q6~&b)JsRFT!XF2?plNPp>iRsS<%7jJv6j}u|C7S0^@ z2@ze$Bb|KbKbRO^Qi#tOgznF|mG!LA{+KXQB}zQ%R#DNrtOTv6fw~MmTLucv3S4Nu-^SF&Py}$q?*$x6Zt(L(}hJ7uaGa@0xNh-Q~p-DaVApLuFy5XB?U( zT;u(PEv6PX!Mi#{LXj7Kfe^i1BWPCQUR-=Uf_>Fqu-Zt z7=Gq%SiW^gW?pM^mnZ&_E8hCtcP(CBzwkwRkMU@fa|TEKpxK7)VV5L|<2nnTStHU= zS6U3J-_Uka|ES9wU&kRCr5Ngo;M{ojv6oBiw8#PJznR_|O2dROl;ae32fY#^NxCWe$(}UiTzt|8u2Y{4Y z7<=Av#mIoqB!b{bk2{1w3V1l1>*V|EY9hQYD!8+v{saB z5N=4(a1Fc&?`JzVanLVC=t$#|yb)x?RmE;EV_nqN#;aLvY9z4mFlBpkG3O;_&6$EA zJ%~AKfZKW05?7K_bzxiEL4;8q@gQCbycQPOOwW>>!pYaA7S<4?DM4fvhfD!T42wkDvAuwBU90jXSJfYN_)aiXTJV2R0dW4OJv0@YGgndwhhc!?*R@lw1e2p zd`EA<&C+Cvr~NitAVg2tEOg?s`wlX2h?C*A|d}PQyno=%%pEYh&KXoM#nYsKu(Ucl8L>;yq-E ztEowu8&?Ew-AEZ7UqDacGwiSQ?C^MR03PrCo;<+gWgExO%`LcYv*9Yy1m!=+LOQ-- zA-A~z+y^F{#?-I78kzSzY>lZ4Ha}-bIM`DL$GcV%zoZA+60i3M5j=r%5qG*5u*rgi zVT07`8wJ~Mvq8YXtmD6^yL%Yk9Iv<cy@)TTmZ<)W|$0KIO+ z=NlVz_gRS)t!G7DA|Wslm{Kpb67jrS%DYe0``JsDXry=-ta*u#^I@1#SVhpTw8(UE=bsPfsc~~`O_EsyYF`_Dp?{v{D0|Z4ySo{*Y->(J-ykW<9&Zg$TMn- z0G^6EFeiV@L$ucF4_o8Yh4sdRHOkfip@;AE~i5CBZ)2)xVhriEp@;R zkp$Stqpu`{Fvv>U0PzVx{6Wn)P6-5b@|cD_Y(N2+7Rd-3GQYN|3DiLHGSmzYbOi!} z_azXi-C=EdurJWBB*rpb)A+cC7Db#nY8up8p8RW@^UzVv0>b`UBI#F>O|_pM5ep3d zuSK-$zmiyA#;-sy-H>0K)HlU*Zi1Dv5a_coVnfjHx~mFb^WzeME&|?53`i=R@N1)K zAV$QlQ3Ixl-QAsYASz9ovi&k}YOr4#b%Ou&^gngi^ERx3A$Ha=&LBBScnX~)h z^^nid0;2?3tLBezKL5)L16?66?qk&ykFs;sAF8Qt(cR)aK&9{@=j}bvpm)7~zh5U-T`<3>>=z?Vmp}GP zAWX+f%rhP53-76Wlm_!BZ!6k!^(3bc2~IY-Ze(wDSIHcoSjs@ef=1(Jett7Gbb@8q$m#o zOYh&{0bK5|T8n?pEl(_`-6qHKmsVCm4kMl5Cx$Gt<}R(i@9;ZVSM`!?OOuH|Dpis_ zZO)VS=(yQkzLU|e_6T~9B{vYoMc=RGPf@5pLZ<%CGA5C6p;mt$*s#!Z1`#@;c9;B% z9@ibWCq&Yv?v0;HG3NG5tPS-cX)#X?OI`GtewY`OdL8A?hHTee)LE!;E~e4hclA()W*IVK6HZ9r*!;Je{3%Na=H$_ ze7d_>>~zEHsVtL88`lwX`*T*-Y#Fydb8|$`#dAVA3;pH|oCn(CJO>Oj?q# z*7Mmy&+YrY_k`%nJWZ#zI`2GpK-w!WvtjzeNU6Dmb>9Nm)#g8Zqy6v2))EoN6gNuqAS4d6Dg07eNa%qhXCzw^cHa)aNd}M89H37=R zC|791Ly}hk>#Isrrne~Pn9g*?6+9{oanlT*qpew14kit@U^J~hG4d(r0vAue)kS;P zOgBd=C-Tr4MNyl3Px2kptdrBFjC7=Jc#G}yopPDk(T(R>bCRA(?XNm>t+qcec0=G@opyEc^^J^~ifiwLXSFt2 z57;YSvuLhDUZR#nkCprS*6vrMjqon&JJo8#S!_=6&{<+MqN6jn?1lbzt5{DzXZ$0Q z@%|FZ7L(6r?K-2`htl4VTDd4|Tj30Gm)x$NTCzTOtCnno4KoxlWkIq7>JlOW$5ugW^!m)>t2ZIO}uu`s}jXx-C ztyy{&(ha`fiFf~XqZ+pplBX|T^?c{IM%7VxD0xn#={VfvF5c(z^|qyr`BiJHLgl8= zkhRziU@`EE8=CJO>+gGz@a`PTq~shd7J0uz@VNrbCvNVOL~^F)dF*e)TVUc9I5MzUq9C`)q{ zz#+Vl>tOufJ=$3=fB33${$Qqbf8JO##Q4o(%kS&p}C2X zWhfh#RyFZTL^MaYf9+e4a-$1?3_CeNgrDqeIU(h3|Dg(d<-vnDG4@fKk9RrmOQzv|0TLE4(L8?;AG35-&*ddV9O z%VXEuzxnNo9S2Q;+y}q?B@Zm04o$EvH5cfs12q^X5RRlRZ*4;*RcA*YDkdlM{sgB~ zUaABvhYkbe8ZW}llTWmBp7p`h$g;z>*G=#?DTH^w(%r`Z@p=x#E6530sioO(#}>0T zt%=RRT|5P5XiV9Y2mcN}gk_|>U9vgum4~#oS#JoIq%$@0QAa3`3|*^V>GXD*j4wbF zj?Gt$tdRy0Hi=F-YL3roI&(iS4pj=*-@9_Zdk$+Qre`kA>-h54jn}CS@+K9)Df36H z2?{d6+WgJyGQ%CZweCmwq@0SO`Vu9LxO$Z58Yo-T)`ouLoZ@bQSAFV8PZ|61b zj2$VNAqbmKfkSL}#XxWc5Orc66N*?4!6>e$h(R$n5@`g>4B)ARUGhM~CIHP1nQaZe z#5&JkQjYv=xmOq61whdDHd;h#9#Cy_bC0NgDYBdyF5I0MqfwDecfn%xaNwB$j@?C; zJ*8};!nvpRt^0%$CD$)2pCSTORaNFGo{h$vB<4Z3VV#7@91CQ~aLzIbX++^Sfk`ZS zZ*&L1tLd@3C&Ax(oC&MeKsw#Kw)duLM=`l&d~xtc25cLdzsKdQlKj=O0eSjVn=cV) zcNiOvi;nlaGwEH1K5Gs464$&?|*#R3`b)}dI6TkTHgx&>#Ju9KE@ zR6>;a^<=P$@jc3hw zX0Al6%m?ysLZ0QPGrwxwH?cX#HBz_lPC!$n%oE+oqR)|jc_adAT`iIKjK!&?R98^` zCk=gNjvVWdf#@K{>)ykT4Lu8cZaq$2=|LSZM=u%&02iLmL&OadcX8@w%VG8)>GFd7 zhssmOMX(x#+*!N5H`9-e#<1_T_%C>wzlW^;;(RUW8G!BuWB^CA9^YSPP?|6X#lL6= zyHYmnQl_5aN_}{ZMqqV1d>QCe>KjL|H#c2`4}pxi6k{OOhq_Qv2zSJOVGXOSjm-?j zV=ng7RkYa(F*ODDJ9cUjCM_aU5vP*pZ{2wLG4IHyM~s{$@~=8x8rKL{ zlW0pWtA1gAa?B!gF_zpdOYv<~fD}zaC0x#Ngw<)EZP^Fm#6r<~pVB8RN%@y^v{pE~MEo^o-P{p?zHWh=IbM6iSC@U9lsXR<)}7`{W7m z1E28Ma)i#UZ47;$vG9~ei%OF$aNMkrABF_WVls|iYP%bqRV&t`UVcBsD=*K9Jtu!o zM2C4HkokotOwEwDQSWG}o!-$wp9!Og?jD=xH)}=e(`BsIRU4Zc9I}|?A1G))&58CF zQu3S|YPZ4H2cq762#G&x)-P&;-$BQ@_RJ#=QdGIy-{f6dU_w463BwhuQ#>O%m@rmW9wnZnl ztY-JAxWj|91xhl3Yu9FqHqJaY&;>BVx&d(!MIeCBUGo@E)can}q7zaSi_dMB>bEIY z6L9wiaM@nh@nC1fb2Yo;00$d``AU)@^V69gR2{yS?J5Tupcxr@wFUt(VX6x-_wjyP zfFi!78G*rA1JoR>F*-p%pQW~LYuUes=5wP;*e0MLIm9pR0+?Y1DYU!<#HNuEVjkqD z6VTR&Np_f(F6^OV9W3xiqnbdOF|ZsN0?&;?5iFp)PbAWylXn}Gh@bO`3-DmTGx*Ua z61Z-Z_M%E`fs+#q+XdTw;;8{^sC*qq$g(E%LC=DqI={9FgbE*5B<$e`kq8EP2l3i< zh6Pwom>r>zIn)kFhIpe_Hgs>FU)Mk#uoIg~ATo ziR@zX^FjL-MHpUyvFz-CjaLC7jjr;w0&Q}9wiBa_$P?0qCTMW7+}KeW<(4~-Z~_z) z91%=@&Pc=Omc|t?@4pTTBTFGZ38c7Q(u=Il%N~{Cmy>Dm24-GKgZlU8G!fiSbac*B z**AHu!&UXStS(C+?~Nb-z0Qz^RyIhL>2t!k{lnfvD+TN#ftt0t-vz7WUP=Qm@)W znMi-47{TzHwQ)zbBgxR^-P%yB-R@EUH5PhKTGspoYMG*QLn;@S3tZv)o$k4AEn^~L z(t(J34D^?M4={peH~@*U16HD;``hugA&6`ktVnJ9E6MD6aR5Zfw0_gZ%s<0w3-AYf zjDJ0F@;cdFj~ez;MDrlzoPO>>Mi>34VO6)JlID|;UOQ-9%?l0KOypntQu;s7+zj46-x zxU2*Jb#mH}mc0SYLkmG4Qha?Z90^J7y(_x@yEKnXoK(9}$LQc^_cstxtUHB;pgxT_ z4`Z`mk=;59@nJJV2lGLT7ew2G(@uhb_v?IxBj&hb7{&Bgk{v@NI_M|0XvK54AvBfe zywcw0Go-OcEC(i5mI4Kl7b1+)M6*ncPSvxe07SP!AP(5zI6H|1^7TpYSI)&OuUDbD zAhnq*Y&l1!-v&Beio*0E!O%Z7y$+OTbp!zm;T4XhQ+U#n+Y4CSAu z>$fuiqp_>{-QA@|bQ?D|I=ZHDTheaC*oKv+yTE^au!LVb(3`*ep?>Ov=>~_hOk%^| zcN0YAjUxlXpO7?8bZ-O}gb0b>2FTqM&vFGq*qZ@eZcErTK%gDTf3%sI41Y^4S=P`; zp5-q3 z_rO@33{jM>H6DYVH44G(!@>Ds|f!9DkOP?Uf3zk@azp>qfPyN(a%MI+2Y%(vG<)K12583d55LZ9~( z*l)d2FcWJ|osUMzp zQ>wiJ>NMFt2zfpFNrU=(w8!6TiiNx> ze35@Z=ezB*U%~Z>2Iy*c+pDh^R28&M)k<(yoL5#IHD$U> zoL6m+5tm}&j}N~`!U)oN1j-JE`Ar%wI}1&>yuXtt#_-C|uCG~!;euy(X-tTr1hQTq zd)k&+ntvfxyoK|myA^aY8NVl8`d;k?S&5|3q8JXe%&eB-;gygeoPz6RLRTo>rg^fY zz$O$qUM+W!<;)ZDv?xTaU~p8;q}fZ34Qb)!!?VH#-kF_?tQnY^X3wS>v(!t)Pa3Yt z`*_u6rFD1HrEn#z;X661C!K~Nw8yj^7kV8xEwSbhX~dvm><;&fw@o#zL!$4SpztU5 z3x;nGK0qu%Y-G}pV(>37!Iyv(6?=NgixpOvG_o-S&3G_Efts)b%elQGfuvUq5E6qT zYGHLPa6-v;PTvej2rTh>H?a4=>39u(626segBlTfw&)$uyQ&Rc2_D)*Sl8yO&~oT` z92|DUP37%vfrwlq$|IL`tR9pOdVhSspMux*i|Xd~HRRi_y(CkyYjS)eb>i%MV^t=) zo~7RwNwd=l7h&Z5=%ZO6c$8}NMS@ABX+tHgDMa9htAcf1L2t^$`|i-$bf-j^@@5F@>qu9dzI&R^Ik}!O zg%B}#q~Ut)&B5}dxPV@h%?R(t3-08tJ$Vc~gXpo`@w@xe+%xPV-d9i9xOW(fADK@n z$Z8c*OcC6s5Te`6V2S4okC(nI8?Y>>D;~`HHdFL=zB%IK22$=r!5SKUYO1uF$9(=@$OZh4`wL=**QblIQB4!Sn5939OU*;xupDd7@ z7E(O^{*AD7ZL?~>0o^8k$a3~Wn>mBfIeYvYy)Wc9$3sn8##KwrLVQ{B)Go_2J+Ra7 z$qH*6eR{Z_`rR2O2hp{1-((@2UX!wJT-s&b#9Yd_N^DzjB!8yR9tZoLgr$JFQm)DK z2+PySgA5LO&u2SyA>ze7%ig6mtJEcY+s@>jafdA2H>i}A%>Jvb>L0!CvK$1Rum$-1 zLnwhn?aKFnpbF!y+w?#f9|{6;6m>uWk}he%Iu)g<57FR@5nYl3zmw9n#ydf6}Rgq9*LSV@^6rD$?km+?VAeaQK3bbd=)H%S18W<3o61X7@Iu7y6JKzAo$<}B$o;!dm8bha zH#|5m*u%$VUD~8O9%L1S^~ze29lr?}>^UbRf)tYN?xK)#4nVyctqdy#j715}gRH!Z zR2r8M6!AaGmSbIu!C>ymHG8}G#0nfY0EE%86Wwps@j{AA+w>hpKS`sD$6#Md5tfr) znhRfa?$>%c4BHHs#roKRcE$>4IrPt5|gKSqC4+dek79yWJ(CpA8+dD!3+~{^L0MaX2X2kM$p(j($ww8%`|t+<(vMs#Z}^JnH6>@~v$53VZ+H z;SHyjH_o#6zrVY=(qxva1HFC5aN7P6qx%=F%RiQvN@3m~|Jnc$PQx7}gxA3!O<-vL zrLgu8kCfn4!+ipQPn86@HId+k1bapnF2`P9m*SQJuKhBKd+lZ>@Hr5EbMj}_1g`h{ z#IaSut;f2kIPt$12Qn7)((?ha)^d0LzqRbuR4%G2^hh%FYloB-J-RgO@08$II$;0U zm{BIA8*t@<9s*`W3k(qBW5)_W8l+MoeP*fvS?L`Biiwy$s@k?z*RS7wy9zs`90X7} zW&o8#%DJeb2mv1wNeWw#<=nh(+|9u$geAQ}hV`e0V1LU(_J6~{CwdKlNZ}yhCD%k- zE&0COsPxk_OC*p>d3Pk36epOkdtNR@yEOw)$QEVATm*&-8eerU?U%E3oL(4p?y9@h z?nqaW$-VH~{sosLoSOJkYJE!!+cabyyg1tkX@S1>USlx!l)f|zIV@awsCa|JBW3v6 zxyPTc1HZ_r?u+YWVvV&;xwV~^dAzMle?_FAV}BrcCGYf8(ycO=N}15^cJoK~=nalG z?p(EMXu%n;eg4RwVKOUg_X^TD@y9;FJ&-~h1zy6TuqsxWM(G>B2?5#fzi|-F{AhiVY%O&W485Q53Rh-rz zo>fi(-1hE~DaWWYDn#P#5wj~T8J2{3!%T@< z(9dzupGV~2l5c>^zwd>}kn5mQh+m@Ux;jQ@J-(d#`kzJvwntAkO_NKI(K~U&c>52Xg z8EM_YrClt{nW@+&&dGlecwYpU{RC^|Z!>utR%HCPw^U)j^!@$rwIAHMhV8c_OViF> zK+_klIeIuv-F8)ETe_jWqRp7~1nm7^?%DZ2FGb7We<}XXB&QJaa%6wxh@Uy5i$7VI zn=FtD6_WHL$NSH&S-(&o=j%8WmpnLR@P6xg?(3PqUVZ-)$K$LJ=dZgM816r_Gu~Bm9YFW;q4m+yr$mkGx1*a$V2+9t@^Dw7 zU21>y?tl7xt_>{*z|YF{8&wd4xjK4C+k!QA5r#TfxH2z`4gqYrGX&tu?kQH5M)ep7 zDfC@&?nMTl|4xy=nrn1r^ho)j>KVxh{ue8Ov)9LWVM?_jt{I*YU7KFqiSsTt`Zb>8 zjSpTrt{gH6o*Bi%FTZHFjA&V*Rd#f3p$}3&`S9l|7kJpUYE;M#7zQ8nwOmqjlBHrD zfalH+MOrl!h-f6_bh?Z~7=Reb+rQ0nTJX@(K^Mi-)nVhUg7jGJD$-mzy#4g4=rJ|_ zgm*eSs`U@HC{`r#k*^{1;XZ4}cisA07fa*QrV?ICsMdN3N{bff&{=J|EI4R?)b@>b zwKh1NaR5jnQs0g8vyS_7f4MfIi7`65c&29J34Q z>T~ThC9$p_zXoP_-qx0R|D{`kB}LW)8--O@_MU`Emi&=bwj!>6Np>59tk(rDm0aAU z>{21`Eh&$o%VXO(?gUh>G88iosCuLg;WS(+&V5Sc_vmS2T zyN0Jkml;E&FGPxdGxV`g#Oo970-*YnOvsIQxl@BbAX_m;fc)*JyIwjhDXhQgEQXeG z5BHdst=#$)CCW&1EBxb>bGOS#hj`5$gQYEh->mah!un}JtOZ(x%Z8EK<*!N*6kY2E z^&grT9hHW67B9Sar+6N)Vs}N8ztUUzU2XRlvq)(ZJ;D;sbA2Pm$vl&C1w*6qS<+P( zoxf@cSy)q~DC#9lwB!;A7xL{d-1b}tXN`0!C%6^z&GJ=FZ77r7%y;glqSZK0lc8*D zchE-RYZdj0-=HLYw;LAkfKRdNUx$)-b% zA{|3kT$JpIUu#klALJ|s^u$^P6}*=)XgJgwh_S& zHink_lVlqvwZhqHaY~04wdaQw>E{Y9wlUi*?3W*{P>@cyi>6ym5BH5(^M0X>dwSX^ zs3ff@EZOx^ACINbutR*l``D&tBI9if%*7>p`$MxGZ=>3Cmx1`uC`!W(@vt8SKf;Iqi;9V?y8tk1 zhG?ksflQ?1!M6Nl@441nEVfAfIlkxJ#e)j`E(+>vYo$jKB z6PYV^I5+B1!!v8t4@I@>F49@hizn4Jj)ybK1u2w&ZtQAYi5mUttrP7n%te}7xw7Xc zQ!xq7J-NAiMkduw_52RQ{4rwuCqLsQ`N#~zuZUusxr!{ybzg^Gnk-bYX>IgXIn{t_ z2$ee~s=)`H z_Osp#WbbaPTprnySHiPgv1`Skq$vo77-N#l-@R=-2 zzYvKJ&L95rmG3*W>!sH=IfP4(N|v_WiOYM9#RKkZqwQ*&ln# zSJTFVL|!b_AJgooecxetsJ_{l@cH}Y)xWnFpxBNc|M%aP*^9`66D^c)Q(0Ab>8^;p zS+u?$-TiK`JT?b_Uj<(S)EjzUNF6Bg;lh*DZC`m{yas!v{K>I-?tkJq?VWThm(y6a zxd9e)$yc~K9EE_}&5+lN0_Ytm{LFH^;scuMPDXjgYi>*>yzNZK0^hqdCoQ|s-vL3f zB_kxBBStCtV>JBe+S&@Q5Fui9-A#1+3XjiE!@%1CL2gHv3bkCOT_*mumx1Q+#v%1h zbYsGopSy7jXar6t0RzU*-@Axx$pMiw-Y=u0oLF6EZk_GO59t4spN8cT&^Rd}P1g&I zyI%+KG|)^Fl$|zq5+vgP^RSu#8i9NE1_9&wf9{9KX}^1#L$7Xl8kC*u6>)LQL3W0| zZNTAE#ZX}nY)+!77+EH#-S)=NV!Cp6_9dvd*4x&@y`kuYwiV+okKvpIcQiw;9`XRZ z55OwzISZ%%A0y^x$54FnG5HP2&D&?(3Tw}+E##jMGjaE4Qdxf5IvUqeRm*;dF%9o^ z;B^v}TGc>4Wt6e$LFEC4+(lSGx0k+j`}fPZr)HG`!Xu$yX<-=xg`3W1ylM@PbDwbd z@F>?u)}x7I5n7)6Q4($;K#IdzEy%ieXrq5-*%x`5fwS)~8h?&ze(NUO)~!?8=Mqm7 zPyrv@nu~S9O??!$XCR>Q>E@vSdwvD%3!p9-*V*Y#%C*1YM235R!+C5CI&>^b&s(0- z#VQEyU;@&=;qsk3@tyoN~nb@RZ{s9KPx7{v6& z&O6=SvEKeR(5;<(5n(5mp!8xP~B zA<{%|vTnXuBrz5MH{{l+lJR!zQTYskx#_wArchziJ5BQ#;U}Kvu5$f~{JfvlL?gki zHR^jd+u$Jh?ylY=O(ZJ^TL<)Q$&BjnyE6%~z4MR*6E~44|fK10mVFNoY3-w_Hjv4~GBOlfcp4w=TBmq)Y z)&Utj)n)iLqVqYHxI1a(8lkOApG3C+C02-=r`Nc2< zOId+|Kw39rPv@ug$^c!3DESOuNTxRh#bOc%GR^yLGRi*iI>X)G(pS?1^heh-C3c;+ zj0#3-7rKQn=XEANnZlpT3XcY>DCf;Q*qUKds?f3^!M-MGD>(mLbKcO zb{+jq;&*}YTfw{|b2y60D@?wI&*4+i1IMpnVNfsjCvzfB2EASR?!-?VN`0#$6LhvE zK(k)_K;5B(8EUjr=!1$V<$*NC(8YOq`gg%7$Km?-Yld1m)Q-zh;x%*xb$msiQfTVG zc$RrlP#heJwnA&<48UUH8d|;6@GdKfPZi`suYFwSUiVD{C=+Wyt;Ra`bNQiQCt`J{ zV`~y%B@f$_FKVasqRU57C-nFFjqG36K*00Sr%bD5lV%L)0*`$Bq{iKopa@6NAjkX{83&k;=_W8 zVpsPq;zB391!H&rI*#~>4~G~ZS=u)bTHX9@qE;8mha5LWhZ?EyZtJtaV(VA~_XO5N zhs>!X4EJmOwjjN22#)>V||8BZ?m!p$|k?Xv(Pq)9c-Z&{r6j#nc zzSrdd{F}v{VMgPW%IF&7eRvS!<_vIXS-_+3Ypxx8am;Jb%kr2_57n)a^R&q zGro+0slG1{UXea|8)#SB7Q@c~6nEuk! zQR`_fyS4>9k@-A)Z50A`36h|z<_9Uk(Vhz2Dyk2+M~!u*K8ph{IrC*@U@GWc2d}Q5 zq}{9YSK5m%*czmGc{y_XUN274@X&fasgGjObZy;>-$sDJMPS&xtk5`=KOnlu zzIUZ<0P*mR*nWEREr(AF*{v3>l0iw)qpDQ+ozZz9{*}E1k=Kptt_#e<1t+EmB!6Fa zYRJY9U8R4v#Qt^PKIj@TGP@9ZYEkUABd+reCxr3NJZF*ea>+GjlXro9Y{8UU8u{wU z$5~|MA<`O?aX8mKC5PF4h}eZLP>_KPa7=k3omE0to@w1!MOH|^VeEoqA)4_ z+U|wj@KfH3@b(*dQA3AguYxX5*HVv=lPnBr7+Jqna)u7XCO|oZlq>Hv92ZtMq8Pbe zEE%kh%9besIZE2Y!P4~Grv$OV}`p_^8Y2O8&<>4qgW7M2RQS=JfnJs70=gXqK6Y7(E7&i2C+)aMK> zqm0XH96NcIpG)+Fu%+`9(IcZXjf_2B;+q*|i(|DnDPZ2|hNf+F>X8!JxG}qGV2N9n zes{AFd2W*Y#X{VK1L)?mH{d6}e4G+2%ffim3VW7=g*Qhd5*-MK&g~SpeQGJJcMX&l z{g^&{YtUuFjMJ9pg5E&Q{l|GCZ^n&#YNc^(`T>~ZCm8)7Y~Q>oqm08%5$jx}Z(x*9 zT1nJ;z7*iFKJE((!2#Uv-yQCM<`q*G%e>jnPDxm5qb+U`L0^#kDHS#K?{DMw*2w?D z^|wO)B3yr>B)gZj{tbtJunTZsZ|> z2Rt!a!01&wFEk}+u!5BUW<0n2^1p2dR7pkwObw@;13;o(3DCHzg2KK(o57EOb8n9% z$?y1mYaPv+7X_(7!&Z#}(u$1>P&Sv&4126Oihc>iZsxy#4PeK_013j$YhM5&z9zyn zR_Ct()b9iq>t|lEGka-ksDR%&{~R1Zc?3x_KyyzAYS!8K4ddH7*u0^g__jU zt*@@>ASpdR`0RU~659+E*;Nq^Q`hpOU#ojCt*{{!^*5Xe61 zAV7}^g@~5#W?@Y75TW02EOTMN61K<;_~N72u&(xVs;FAsjqBK6qYY$Mw-i?PjMkr? zbfyG&|1jm>j1%D9+!Mk+H0(vK(PINS82O`u}{atL?9*xcxnEV|u#;s4^x^aeo=sG4fp>ql7_ zUcjEK2eO`QAcOR1;F1N#J81UKA{3z%z!)Mv<8}Oe6TUV#8rSzX9ZdgrpXz_R0r&dd ztlRagyu=tJXhHUu(;%|liSs&(zx?ewvcF$^7*Ol`<;T(ge43Gz$^ZP$e?A!gxAo^` z8^d=+(L-iC0Aij2s8lv%kyzI?&`+aASD^mYlL_@e?=5AEz`I0G-f(B^eU0=W&v@-` z_%2)7MFLpLinwdn!8Q-r@TXt&c4%I1{9<+mYB4nekqxV%$7d25c zZ+#8BPHaL@@7qJMo~)RCw*4mnKM`1@eL^J57wL5lBn?vQGXB;m{-J&)5;AiOT5y6l zT+?J>=R7LRM%c@8+GfciMs-IzrB;6^X8kB*=zTHxpIQxt-Ys76 z>F{KlYF4ce3VAVVle9;Iok-ah>Yk!`VXht4@Dx|4dttZ@ks=gC){5`u^Pm|DRVkcP z6MGUYA#8bKXJ!;}ysPO6+i3mKwWx16veYPrI@@8$Vw%Y}oUaC|7+UZe$HA^x?C9^zxpvP z9OgQwJg}Y7J>UzZ5$ygrw3eNrBIf%J)95W`DKmpHu7)DHv z?^O<(Kj}7O;9WU|M&iv%`8|QxvE3?vey7unt)BvQ5(0`4Y(!I9P#>lGZ^u7U9pY&{ z5NsJOX)ZL$>eq~F-aW(=7RL9Z3=eH@5I1A&6uC(!6azZo8)WQwSp7m_v^;%8KI~P} zwem`N*VDEbnK!Dp$Ml}EQ!-;~o=fn6K?_`AKAPtAy9JRSQSTwU6hWyQlKdYB=KbZa zH*_*(MO)XZs0xdzcy^m>r0TtA&-=R5@F-W2F+h||&3U+NE6rXJ#Z-ISm&^zTMf2Mh zA>HOp*?g-;?#AHboK#S8ZWA9A0gw4r{JhXv2Y!8m;MO)@r^8I z&#?D8esgp4#-gW(9ewlTJQ=v?uCf@~bYuzos%j|4gjLi`JozVMA>I9OmLGs~td96bN1kYnOA%qXP*GWrS#d~xSI zra2;2%>X>UJwo>UfoKI=Njt;wi5%v^w!NKKkbO}Y3K4Zu;9ct>+Wr*T*gmWM zY7FJe-m45eQOMUfJVivZJZ8SUMV2*4L~>p4vuuwJ`i(AkdK#1048L;;32i*^jQVQC zAQj!d{bn3&`usmkVMU&Sq?6Om@e8>CHT?r-sjxYKVLBva9 zul>CGSGuI&!KpDDHU06}nl=hEuKt4rvln01x*feNn^eixytM^cE5ab1VkyhGNLW0g z=>G0ZbG5{Sc`@ZDU-jh{*%E1Z$##--5oiuf9bN6aLu_@z21oa&XpyD&eC91YiPkArp5nAGhTphE)i7)Ma0UH)$1wBnAI94XA zRk*1M64OO6U@7LNFYfN{sfK9Kr1siV@=qr0&(g&nGx@>S>90+_|H4ER?o0_%0jgcN z&!*eh3FZ(9aWtf@Dz2OmXpfdQwGf*r<*MRG>NaZ**aB#jlWDwV{+Hi$`k1cDL^M+p z1pA+pO{O49$uh7h;~O*i9A((S)7FTf3z{xaHwlQ&_wh=2S2;N9jgYh%&fl(~TEM^g zQipV`iz!fb=Z-e(IuY@LskHUzo{gw>VKR)%xuJwG>3P^_sLvy5RjLP_VYPAmzV5=< zd%DRUHoB&-ishqfpRu&gRnvFWpoO;AdoDlqjd80hf8H=}zSq%SZ;Axq3I0~NVkb~_ zsd)`J^tzD93jqKxRy&>yW8X5js>5McJyQWU2!C@)y@^J1`G8`A-Art4U#6kJZ zuI7|)dJeCV6v<7RInepPm0egfIWTeDizY`tX^{%w@F4dkkc7M~D1NJvKC$XqBNUP& z%k%2iVN$qHV%-J}=nA4zupaO8V6o?x-b6KBLFxG{>q}!l%`ZNzL|A;rx*lc*rF=y~ zl;3nTP&`xjOKsCX@4*T z+T>)#h70ViPeyJyd8pW#Oot+k?Cop)WCz}k3Q2qo~Ls?Eyj*vUE@Cz z43B=sPSqf$!TcL?PtEz9tXQqG_!lxBs8~_9Fhd0zH6BB4yc!JQID7(J(l#8y^B1!l z_86}k#zn3pNbl4(Ka5Rx;V>0Fs2I60nfp064yry(H5IJ_mK340Y#=PpP#|A6_9yr} z@=C4S=|NNV>-7FZ@6OH){hN=ec1#jeJRWd9DY^FLMsNWspVDF}jIiBdy_|$(quIU6 zG?07qIa`xi8Ki*8CXKK*1l_y3O=Ho0&*U zO^)B0;+DDlhC`c4EfrSwwvg2zlJ^Trk4NT6GgM%PEMnvMm2_zh(ztuc$>ihWFGZ+$4aM(;JQozr zdrX6(ebwo|VI0t=SCGa&6f%1l8vVvZMWk@M?efi3LgC82JB1=&zjpKk7{TQQ2{^mlPcC)kT zWv=D25xcIOQeax;K!D@5DjyV0KFQXzaGL%^M5q|)!+l%E0w?O;@W({+1G8H< zIC~LAq{h=?CtdRPUds!loxpqRY-Q1Y(fN-} zx*uwX~24vK*B? z=X%eiDYN0!5%yK+{!(E9%)$VW5NIWh83hEL`Y|cjk4*uICnI#^rtfVQPe0}?4X~;Z zR(fk;ApGwhDa%z&JEPlCAHN4#G?|uQo0i~!9=$T1f&k)8l44EK4XGlmUx5s!Pn%i} zl}2%4=5FYjlWWIN1tF+{`7?c_1@>snQj^?f#zjt!$!qtDsLP7_IKeW4uj`7S=h}gV z&fc2L-kM?kZqPdY!T2Z^WshZnBBc<-CtF}ZEkp>AvorKnB|$?`Cm%4XTsz46eV+2~ zX9uwOS0FV24;iUH9)#=xAS-<~q!(;@x>k>jlgtXn%3^#P*F7yE0N4@{P~)X3-`)+x zOMgBJG)FuHT7ef~4rkEH^qNf&Mr@r0(&G`&!AcglujvV8*~p-Y5!2P1o|LK7I{3kCtOVW;_lSxjJwjpN!&>4 zdyd*JzaqtPZxikAnQQ===zjUfSi^rl|F;p!&;OZc`%CW6PeO@5%bf$9c<3tvYiS8B z`s^(A`|1g)JJ;>+pAT5YL22|$pSNv46ZK{zIs5^%{9u{Y;vTwupF#cs8_o$t3R={( zKa*Lnun(Hq7aoUHvSOcuE0GZZ6c7&?b-}_LeI$XmrDYJ)4m!j&I>6qN1m6ItS)!1m zo#kFjU^pkE0GE#q_rDO${)ocVpotC;fYG~Ak%siJ-^E5qn#F;kv-@nnmY zM;185$-fad)CKgTdDB*P_L|Mi2tI{T#h#0R=GejKOn7&fRszIj8E;ihh-Vtg4>^V{ z5(3dRh|;KShL8DkgIhLL&syeWs1=pBng>>?A~sKY)|50>`0}nK=6FtCIyaV@0IzN*JH62y zwAxUi`U}0Sv`K7Ew{5B8$pUOhwWjw0(lxs^8_B3T{<*d)-V^UwA%S=hZ?7=7&UZji z!hP=WXf*U{WUJZ>mP=#%OTXcM*=!X4hC^cPGDB^P?NSmIsPnu*_qdckn+lYnO>0C> zZe!Ko`(YQ$lF6d&ke5Vin;AE#>w>w_O&^L%cbldPRUrfjS}!KB4g0DqWuLH@*S3Lt z!>BuL%?wiOGWzv#qofhQ#7rVCXL?aT{v7N#>GP2Lqm!p`$F+DeWxLpL`^@qEw?$mC zw_77y*KOFQYaw9UYpp6~?J?%yJIgBRQ%iP3z3a7c(+UH;4 z=Lw2-p~n~0+eWjwU>bWqMZYjPrHsKl-~th>iz_A@BHv5FR4T+2efrzOK1{mUAAF75 zeIy8w2&Zon!wa^_7)beP*8sLUJG!+vwP02EsH{Kw`C_+IQMNO)26Y}{dL~}AEDZG^ z&qk=vI?lBj(P%rwnYNq*M@9S8H%48)5Ks|#x268!g&vFS*EEq|4l zJt(o*l5!_@_2=@7Ldg<&ke`8?ML%kfTed{3!*JmvQ>A#bV8m-;BNQ(NZ)nu`7p|VM zkb1veCJHNi_b#QVXPEUYmVBXL$Gxk_{&vv+fsB`giv-5ZV*D`aO~L*b5#&cS#H4Mc@b8LOIyYP@FsV+x04MMsj=4{GFC9&su`Sz`4Bj4Zx>InaeNF6 zBN10R_!Q$w=~;52$$>R%R+K2~KroQQB{zfGW?w=n^fL5whqhznVtQ16eY^1lV!RcO zq+18~Ua;m@k$?M{JZdO_`9Au25fw7_jP#@h)ZH*ev2)J2oU*x0iB7jnKB4g#5$H8K z_r`bQa~%t${lPG3>peC^VU#*9g&bYa2o1E6$+XsS&{38zN{HAI6+%Bh1R%B}D3DZ7 z;g(|s2xy)t@UtDASD#@$| zeCTRMG9nCl|T>m)7KQ**S+y?h{iAXOlbz*z!p#3iF zC9%2*?gITq8#>bAD_d`)OMyAv=Q_y>Pr~9wiQr9dj8(IYS`Kx;p`CajoJ)nYP+v#K zX+*NhF9#%{n#@*2*N^2>z3{0y&l<2oBV@#pM(p;v5n&kOIc*=QJ*Q*!Qg369(M^s8 zuu^Z85~Sq$d5kBTQ#L%U(;Fb|gf$Nz*|Fa~)Csht z0h%FAqh(g2@@2cmG4FZCTe@T!S|4;C_@x8Yl_hqs^kn!F73ALQ*L&C?H*nuyj7XM# zY9|S?HJn765Ff2y&{KD_dEgb>tiyhN$<)dCjNcaOD?oLtvcH1t=>aFJjT=9MVIm?6 zP-LcxoSfO_H-QI2bf04J8xAQN&rxDB?kEcXy+`-ZCB8BGmbCf`w69~poc(K5P|y}> z!_myvNJMz?(os9*VXp{oAJ#RI3S(fGsGQWb-Sx3Zym7F3j@mh-G|d;1zGJtRv}Gc{ z7q1=uCNVwj{JO!s8u8R-{i)#Xls%Yh$?f>`=nrq`=9K~f-1trXheD}`yGP{<-L~82 z*3=^OuHB3NOQw(49Y5nvB>(}-KLM^tL3HY@2h~rlYu<#5U6=6H+zJ*T5;-Vz3hou^JGlJ$QY6tV1AoYCf)9daPf6YwjJBY2qcYlA=uaiC;|19XoQSU?b#KQNuPe}v)uv7OGm zXyMdra|PM`R6Jqi{c9R(%$c&YkOuXQI6Q$#i-&9qxARFw=->K3ieK?9|i z^G?IsF9%3$^tqS@y=CND`q*0B?QUQPz48j5uI+1)FFc(>HyL-8W9XUGP;c?T<4<91 z+QK^_{WwJa&38$|p`}F8)${$ZtIB#`Z1k;H8M4l)=wYn8Iw{xL z&fzq(>=GN~NUYH^bZeeI+y|k`Hk6b~idqUD5yL%g=b`Ybki!BCeR>sbpibZc=UeHG zDCsdK%Qx(=2FeX=c?bvml?9f_`z~2mW(o4WAlgygQZEorc*}n7NyEjsxd$)(Y!J3A zt?eZ;jEV3Tq^in+1y^HAx0i|zr~WXkcAh&w8$Rhiuzn;Qot`PZ}`Y%uvNx;9Dw7U2q+`n{|Sw_ zC{vvLB`-CPVGK2+MjJcfqGVYJvA>kL9GUt!!i1a5MT{D+Cp#Bg{2gKNi^R%>*hs zylr5f7IkQ;4f&Ox$6mPZ&-Iz0t9Im3=u*g2?&;?O7D>X_T?)y)NA9N0bILKEzZ}5l zrHelgqB3r0Gz_CKiN9AUGpd=iqsGzk*=tC_`kC$>=giR>MW)TZ5}&MEXImGanw+-0 z_i?J@YGn&iJ6a~)`CDyYg!5^hDSr?uDVdrLBN!QsAtBNa+)-$*dU8xtti%1-J=&1T zPoOEWyMoLu2bbtYvo{7P7ztpeXDXQfW0`ku_8td#H~-$IQ+h4 ztyI`M&RfPnE=2$1-Q5%-Kq`!pMD$=8Q1POueEw&d4gb<{MzGKtQ=!1Zg4B=!k)}4i zm?ymcA@L1#?C+a8JKt0q8^2xuvA%ZgK-7jUHGBPkoZIs! z3Ag`i@9QT7n0Z{*hz*L4RsBQ zOQfw%u8q6aR-0WImV5%57RSOZPL)0mGwSVZ&Q?7Xi?#?8#v8IIP*;{=Hy9_~(0+$W zi(1}shtwT&d|itXHBzPsNVry9VrL%6^BiVG5OOLt02k3Q#M~WNmp0BFd{B6ABP?P^ zcQvb{0Bpr+#K2=>DCLO19+~|3ggPmNx^9k2xVm{Pp%g~s!^{;wAsa@2WF8^A zNJEj6=>eARk9UJ*PJG6Qe~yKmt{$L93MdHPkyXj9<-BRuf-@pu5}8J4d9**59?gzVsKERl{}L4>~FE5eY0)WE1oMh!=0X}DkaH=GX|e0e## zY8^6w1a61{`&;Mte&=@Kn}PDBR=9Mk?+kcP*ePzqX6uQponG4tgt|s}>N-4SIK9S7 zQ7bL`DPX6gZXsu(SVjCze!&Fb5`O^J0!ucX+Zl7*xVmpUeKQO@IbGl0ZUN~Skr`@f zywi$~tIXgSW><_$i1Sk}YFoCgqeE(p+}m62E2cjfp1yy=d#g$~_06RiHZ!>e^?-+z zINs+}Q{O$NL~}IjG>sIY^((!Aw~Hq^ER32hmzOVnx8;REroMo($mG6$!P_XreCeZ? zG*&t^9%&)Wa~gsKX{#6HrJ2dgWTFZ*YzCvi-Q_1Gcj<|(Vva965<#Z2G!?Q{^m&Rq_51L>1$hSBrIU8uH4R|L9 z$T!Z~dflyO0oLBkdw+6eJGVr~<|HoV!i%=}gtNjlQXfKlC)h3!6gEOrpK&uvd`{+q zRJFTTFk{=~c`!tNcd;tu+HW~GpyY(DdW#XywV3E;br8^iD@YwKSsz{9G!LsW|CQ9c z;M9;2%6s_KMFXJ(%S6$0=_T5?vu6TacpnxsXycd-z@&M9Hpl3!=OX~qUSE!!Fp^^@ ztk4H`RiUB>OhT$Z_e6+@o&0rHtzOUYm)?wrkK;Bdb(Z5Zt%=1m(xY(b=LLuJN4#95 zoF6t38=PNe&J3I~6-SLEh>AbjzhJ(eB>b}X)hqhs{1N2K43FmktDWUTcsE!vP|WDP zNg`*fV6gU`#c^rZs@~A?{VU0QSc*ntBdSab)&ez(;N=jL(!jT`vIwj*F22AWvPkkw zA6Hel#~_?TqSx{Kyp#1KxF@Yo!RSDhub2!s{Hx1K+&z2bW655+`3gWPG!#?IDZ+eh z?}B=tSxELE6)hq;b#nB)NwUthG;pQjIfEx@6|U?r*+?EVQ}YN5e)V{)deogqzZ23n zXglJ5`Gqk{C|*>-1o06dXAV3prSpHp=(E?WoNU|z@o@Y%bhDEQZ}2x3uk~c`@U9sS z0mUG`YdpK;j_Q6ie9*I>%wTyT`+PeCVN$flf;znX^;p(DEwY#3u;CgXZhx7OAn~WV z_=O(PJ8G9Y&wI^hbTqS-xqm`d7P3A)Q6Rd=Nwj?26&)*se^@B1!C*3z!B;kV5pYmQiT(DBMUfCN+i@9@)7Iz>j;#KZlW9TC)F3D(3 zt*;|tGMv0D5!-i{o@dS&`DBs~r7~?hYp@C3(-}^tJXb)F-<*Al3Y@TBKE^KcJ594gQWT5f&SsYNu?cqO*CHyP< z{-cKb-5>o|)Nld6OS6T5EvuDAVNUC593Ew*AZ1<|$qz38{^&2}zSYYMFL*>)a}b3k ze>CXTRTB2d7GE4z7;%eV0fBYrv8ASY#KcHQ&xEH3ta^ji5?R{|cRf@$l@4lbcqIZ9 zS_yl&(HjTcsm}5lWbohdhxZ<>35c-902$~;h9|@I0ibn+X};;HgccH@L*C>DVJpfH z@&M#$c)eb){>W>^v{}-IeqR^@!Z7{No5}cJYi0lc)eHG^)_-PozKwn`foPPzJ9TI! zCvjU{ZMWxO4yB!kK0T3HN$wkAt8q?GiCgvEC)~bQWFr`<+_h10uVxI1Pi#OqU?9N7 z6zQwX>@2QT#duhACjcqjipi`=|Atc)X&OFORUWf7ppEv(c|pi`iE&6*MD>mSt!HV` zl0yq2zUqNu4XE4Pvm2$S@+@@-i@IeO0c{%Ndvbv0zukAufBc+0K=Xf;t;Jj$TNE0^ zxi(g~hAryl^Fw*eEP54*BX+93Z@< z6a4_FoM!Ob-<$hATZ2mvyyx|0Gei|V1oA8n?($A-DDSDjiK6qSJpH*E{Y`w`bEY<) zbra@arF%zMor8=P5^!59P2x))AuzOY{}gkoR4u<|KyCNIr>jed_PDU_vfj-wAO8#- zCr6}>=Q}DUZbZ)e#%d4Y!i1_fqzz9OpwCc}3Pa`R9F=^YFt&=Iuq3if&8U=d%&b?$cye2A~RlxyvLT zp4|O<*=upSF~Tx^$!>)q7`M-msX|G$UPkA>K0a5v$E*Sk$#fTF-e_dK+Od0g>Fy(o z+^L%r5eCp_U1{V|`Vp7flJV9^__lmT)iaZ^gK#_k8Xe};f_zTK2&jTvP;S9!2t$C^ zMLa|@@w2~Ed+RSLBsa}X(us4DFJ#Jd$fTFBq2j)bi0j&Ch;d%9twXGgw?fnE67uzx z4$nuq;Z}|KXqDZ5q9t>q2i)tUK5tr9w5^wN!vUOBKeQ70xK6`aUub*j{qly|qQNIl z!O8vZz=$`hUQ>hlM~|1pULf)}Xc!%w@Dygsi(~HL2v4Z9TbYYO%}l1*qVHe2VDKA3 zdS&?el?aX7%R5F}u{NDo*l=;Qm2Nzfu*-YE^-( zxrix>vTdH|5e*te4+Tsvj(n89*~|NO8!xUr^YxVmUgwbRFuK@+#M@KTPZ{RupNSAP?|o#!V?s#6M?4^nShtDJCd`c9 z0;qZ0H6Xu1$@iB7vR-6u*#IdGp@_$GKz#CK!u}4~v9B2rtGr%$R9F|nx%v_5 zp%%oY3L*(k^gNIQX5PtP%2@xqr{aH@rCgv&g;Y2Ng5saXmF=mU0`wHR@R?S^a5X(R z8?PtPDE7N^k$Nr>oIFf0b8~(x0lsj3>$V4PqmF)jLC1+V`b{BVN%wmEyKnbD=lg%R zI&wyQ=R5(}M&TL;Tv*6CpI)c?GX2?XY#;GRN$%Fgww%Bu4v=o(L8)$cx`#QUKS?75 z;+6$<-q2=Ct@F}wa<|+Zvon>t-OzYBNGD8p8dbhLU4%Uk*rySbXRj4SLDm$NZijP> z`WFO6l*UBclM2~GaSW$|=3;bj;(S6(l5NaT`e;4*()D3^PVC(hgfTRa?5w&_PR{Z5 zRrcXS+2!vHmR5u>5=w~}5fc7C z$*-Q#)jV09kTru=rsKE*oc^( zhCsEL6Km&X$((4~5Rm+LSN*l{{;&Q!xAcy#8N}V87bjskO4whPG?O-37KZf`~9x1H)~eD zPct6)p2m9TvWMH0GT7o!-v}%Jo52w57WH$NPPh5G01K7S3|3Y|s(f~6vvuiUnhJf(a96KvH+*5OkDeh zak^f;g0~@5m=tkRokG`y6XmgX0wwXy(QP4`DC@7C_J5WB$U7f%dS3= z->X+8Goptx!TiCmKVR=LGXVNT9a8*#R!+05_oM89TqNW_e9H=JCx^A3tSOGv!5zC# z6^Vmriv3%*u)B2&wu#NlDD`Z*ttL}ZQQa}$EE(IL+juzYrR5?llMAl%tnp5lm9l6f z9_IEGX%#pYFUqZFuIXnw_OUk5$K5f6ViYB zRD=1jt^7ksxdFit14|}cYgt{{UTuy03mzVUc5WYy2{X+4+h~E3sS2Lq_rPcs5=67QJfhS01>&~3w&9kuI zvllph@q5#;moi!as`yW#pAtzRS&2^=)!7K>Inf;K3+$L!yYI|$m7A_B zy$G1V;r$7+3+@A)K3R*SKHUsI0Zc|clAfPAa4kbePq_D5m$#tsC#w3e?y+>8poZ)U zu~{f`ed`YnJAaTX{@tIoqUd+8p;Y}S!v_GAYSLbf_EFGEsLMI1;UTca`v3NQWdqD$bpWjv|2%vQ5<2elTKA8xLZz;M zuxsV~V{QU?wOXxlYJ~u;)6y}fh+Mlu9wm#f*k3-<#Eo4HU%Q2EueAn-Su8hx5QX-`x zqF-ZK9C=K(2VUzNd`OHL4(MpV6_RI=*G~EHinH`Q9WpFMAte5`G!63h#YIL|DC-}* z73V|K2AMc|3BRmdv32VIpsAZxd;HPjV`%zqQrnf*rNsV=La}p&v_=`g=Ia+qVff7F z@!yKo|3nJ--!r}Nukc))z9thK#nR`Jn|kqIW3L%`XgVX3O11COG>6y&- zcXe$|gJ3px^ z2e5AY);*n??z2wS2+BdCXOqK-8->&9r=2((9&^9islb=>kJoc(?8MTWpPNneqkSl- zk-3OuwJ33{$b!gEex2R4{(&yV` zE2XcJ)-xQPAD+7pP{A{)LnF--GP)@^v>o+S%&nf-*X}-iPz0#k8t$AL3m4Y((IkE3 z7-@K)6`(C3u`AG@5^2%P7b!m1`L^>$19f?fy2j&?Yf+i-K2gn}sT4HggYmA>Il9TyF84QNrpN4okQ2lQT)zRB`8YzUQ4H$N|mt*AR(!x|F)Y_Mf@w9C<{ zsvTc4_NMlwuti^%X!2cN1IfPck4wG&ER{IFl!@1H(-haz{Qjp7jfP{E1#8y3!2iU4 z^bako-&mr`&~IEh6efV+&&zA=%BA?Y@3zvN_C{?P;E4;wAVVIz99! zh+#f-;Y6WTae}H=tWCJwwC8|*@}-;06bn=I)JW~T62hmxK0QSAwAPA zc7WnCjwm?rxPXu7EJYfRz;A&$xF6iDe$e^yU9lL9 zI)7ywEfHHH6hw#D4cdm~scdi&`g4w<3~k-#KC#VXpRexvH8jD^S2|4;p- ze-;q+9()Oh%DNe3zI{TOO+(j&Z|gBw5}QA3Uc|sb ze0@H(sJlq2c7Sw#iBmLJHr!4)xgs(q?ZQcAJ5R18dDrn_Xp*9K7KG0_>Sa&9W&Gz_ zh-Nz?-}u!otCEtd669MTS;k!<0C(X4P0yO>8mtOpG)Uo>aw2lyIpeqS5xDmyV-Ja+BQBMT{PxbMRWy=d-)3* z#||~qPEoox7sqnLzd#UVsCj%|NvU45ck9cbJM+y| zvHMHnw$G3p&2zhn@z~%X7(X?o3O*>#AXVmxpTnAv#Uk5yDb=CP)_fAM;cB@4y}Rze z!t-fe5e(^fpjx%|h`V!}DsBrZmP90F_(9uRf(`4b#OhYDY}d0!Iw^hJ2Lwh|n(A46 zEg$?yk~R!aa!c+toJ&bEa%tC*&r;`_&a&)kxD4iRr?hz!O^`=f(kL%Q1s246mzWMU z&$>b&^#odtjm@UO!_+U8lLehh4ApOlau4Y|ClP9N)0bxlzahICe|GBM*B1F!tM}pc z;vdB?sbsakl=#0er{<5i0g!Zv=gqRPxKIa%jck68>2ax9v@%0Xmvs2eG$ARmv3?V&!z5#F zj!qnQ#z&ElFdvCdb4xD~g;J#QfJ2Cdd5s`sT4Q%L6?j=3aUOsNB>y`PNRx7z36pLm zY6UoM?f}W&XIK?S`PC4zAgcAh){{m=P@`^m1gUcE0w9rI#YVC zKismir6I!L|1L?G$(uNSSp=I69`;&wMg`9y0uHaTE4WaVpHIab)B$ruB~q+4c=F3aTMrAod$Y?&49XG z1Mrpsm?vJXOQ%0U@8NZTR*vS_T^Mp1n9T;L=qe-t>HLq?&wo)??e|ObS8lP^=a~V< z0WkcI|7#R0rPZa%3mBYYxGY5xVf?_tKD%C@nNXuAuuq$7u)RCyKGMT7ebGFf;JzDlfBfJ8w&iD?djGwYB5f!r8%mz=8SmoT99ukr;7^~WL{;Z9}TpM z#Da%}Pm9fF*K^HeNS|M-c|&t8pWJLq)`iG}S%1I=nh-dmiNntblL%m#Dj|FDSuzs4?-xSvdMKO0~ zqRubFFz3L)J+=K$5X2s~@UW2zTze@>G=l_YPpj;KiD8^bU^-u58RLWa32ITII|!PE z4b2*!eJkk-g;bVZwcf!DcetVnEngfY&CK1fSyhO4SHto1-pj z^0%f3KV@oD4`^J>56;rK$JHrAGlo=mz_E0cEp(J#ttffG8qsWL)a2+#C}?k^u)!tU zyvY1uVd_QV-O7@U)feI7GCKbhv=saQ3+nn`AJ~^J^zen<)M2HH3u|xzfi}2-%=h8U z_^-7~C!6wkre;_rPAv@*+ALi3h!k7?lUaAZQ4@?($5N;ltv$&x$E zF$V64IaZtb?1fO!%3wD0U{RFCeEH~v%!joo~=i_bXqP73$5BkeVPdKEUIcR0CYlAhwG zqNV=TQ=~~6kJjwR^h*NF2b`y0EQ2^7Tc#eY1=!x_q~@Oi$$B zEM$_`5~kd=ag2hSSuhIeJu2h7o*kzmL*46cz&3$o&tpbZX%cgi;Yi*fr~-rw-h8rW z>$+FXl)w^xq`^`A=2P(AROq#rwUOGZU8A}a)2f9$Ao*|mI+ zEWpN0rSHKafV4hTmuALs;^QEhbN))oG5H+=hP66&W5NN3PDaTe-)PhW0$2y2YoL!p zg>_o}W3T8;8S`aqsmuc_cr~kqgMUoj?B-41Ii)NLtG9nTLE`I|)%>A(3u}lk$?ExO zV~Eq2t%r{O>LzbhtQrX#dBQ_m2?|-i@iWFpirsd~5ATk7)@?0vclP5T69u`3 zc^H#7TWPF?aI%FD*@y^xR`@Qz;JiY*&J>8Pcm|tfX$Y>9v`Gqi3}=7MmT1%f2qZ=XK1@+M_6o6@ALmEg0d z_Vm&Es>S3{icwjt&>-M4lpoC~;5KH)djY5kxFiNuT2Ks(wstN2rg8M~SW&5=y7EG( zG>`pHzs-0HaA7lE{mr%dUuR4HzePDALuHw#TSOHcXR#)kO=oX;gLNo0$fjH0pX8^U zLlwFDR^KP`RfVFxqJK|9rrbQ+XIu>C^TbU;BGcBw;PnKYiak*#Kmaf*bn2Po-2t&IP?W|S)AFEVisj3zF{Lg(uKGVg%qB<% zWgqG0zSC%9F@n#WZX&U9fD}BylcdVK-v>-RTYYIQv_`dVgdO$H#?lzVK>iuf3+)z#`t&X6pR`Y;3jXN^m?<*unS_c zBv=Tawf3obLv!G=b7yt0JPbMV7Dx8CPx=VHmzTF0LW{YW9w(AbQxEs~?91^|%N{k_ zR?*UfR>~Ir339eYu>1r`!}C`o-%iM<8VFEos7A|`XW(nnE$@dkK-({`zix@t4Qq^E zcvBN%^sSciLDWq=xmGb8{Xnmi%jdA}$)MKRdW`*d{35gfQhgyDO`kNr!~KN4vNubp zvRYji^!~(!-B0O=)fjB7B0v=UjL<4oSLAZ#;G#jnI^H+&8y7^c7+hq=apmZ z)fD{+f(d6YBX3DPs-p|x!+I0?2%KExDMV#ifbe^;&0In*hj@#v115n`x*3=^eQZ+5 zZmRFjh=irO0jvcMdk ziuKV4B-A~#>0hWo6F_0`r{u1b4N2FAOYT6CueF zRYVL(h%4h7Qn5VF0cA8#4WX>m8FspvnRVWePII$s zE~np1rVtU*g+!9LAm~475B87c!qBK~szJ&7IlK1I?j-3G*ILK*$K@T#un;lR`L8uN~BgZ(@L@xP&TY5K! z@*s#*Yn(CEfv0BUc5Do0YvtXZ9WaER)f9~xHXt~1@s861r?;NE0k~^6?}euMQdEcp z1@hhDvA2paC+J&EG{q{;)##Wf;2*QO@vBo@3?X*wZl5Q6Z>T$NRK?B{6RRUjn|Y62 zt_AE@ca@30cRSF;U!#t0K6DNQIUDttq^*>3Pe??rf4KYTO;CD$ifUZC8Iv^ESN z!zbd;V2p$F#v|X#liyCu$y`fo4g`5u$~a(XP+?1kcei-7-g=Zy?`4Pde>-(IX~V`6 zcE%|p8Z31S?rgXh$mpl!sI17B5+72*Yr{l&nQ;*cn$D_pg4{9pc`zE3nLP&|FK|dR zE@GV(iIn8emBb~FFGVHF9aQ@nT51-VTQg^o$HafUM;|Sr?8$~Mgb=w^K0)g74rFfK zaHqL_S31A1Dot)4+gIRiA=N~69?DZ8U47gJxA_CL*SBYt*0W#bZr<3E+|*9G7um#% z(6yXNWzh(AV^`zv509eixXw(XNB9_iu8c1uv*ZGS@- zHGV(20(T@?Y*C3HYbF%C?1vxQN)yo^3W*&_QmLscDXNtX7n?SZl`>RSN9`-}2EN=K zf>|5^-XPQXU++3nEQv&H;8XAJ`l&Gb@;AGdVjMQEI=C!mr~4ZLt=^Jv$l%gV+P-tMk8_-4Ie`I8V8F6sdKE zl|i5b{)%_peRuL{0w@35D{u;HOIRP>+4tV4 zj!@9C2wVO(BRCsR_P5^ zf!>5r76`lIsONHuS;oHqrrrdgINdqVKa3bhYcF$XOz2jTbiTH5VSgrv`{9*Tw~^4E z<7h9OB@SWMRpiczqkwyY5~Z$gaID2#!M$N4z7mcHbb(@qS!k1}=gp1d>CY?N@9()j zD|_+o#tX-)mH3`-d!m}dAO83Kw7*&d{Ta&cJl=zr2h@3<1Bxtw z{##BjH(It@PD*lz>9%UjEm~ap=ug}lJ&HnS!*R1MKriFoOOY0rp`I|Nep zU<=-=C-gT*YD09}u)1XE?`naB$=~H`SGUJc+gV!gz4NXg(A6?|>>h9v6xViYKcihJ zfVB*F8ezUc>D?<|!gfOU;FJYwVLxUXbDe$c`skRm;3W)NyV|Bid)U?<}u z;u3bMM%_ky4A-)z58iuP=pCr^{Hgs{8k3u$5`H;<<${6(kc$rwXXs`zpBozxO>Y~k zZ@t2FqsG)wTDj#t-B@BtRWX5i*mu;;OZ<*YZq0UnR%8meZ;>*I8-y!4Dh3ayN}^VI zfw1_Xw4_kUbLlAQK=6hE@BSzFm9CYG^+^5oz4FJ$@Jv!?xkSgj@)(oRBu+u9a-&=m z;SvvU>ZGNAcdkwKdP3bTO_RbT`PSC(Hy<4cUc=0dm5FG^j<)Q(GFF_jx?=NVGV4s@ zv?nK@W$)ko)`X<`EZO-=&tlDGdm`!mfJm+2=*z>o@&VPfErpNE{Leb6%m$ZriKjt$ z=2LB|Rt47xm>iQT#ctiEt{l)+*XnXB)QoDrPIhO{vADiv;pqfI!BMq|{Xvha2E16u z?AnStqsC{2T8TGb^2p(@^X`9Stf3!1Xb(>sjqL0F0uD8KO~BLM+ZfnPq1meaZ&Q>z zcdTOwAt9ROIG|10PGA6-;O`y{X)pKT0K8D)eH8aC=k{5w>;MU@!9sayMx zk058)y;>RGW`*{gM*|49ikewL&X6l3hVKfZO1q7b$hjEf=l=tmZCNPFG|&MA8lTc5 zfK>PCH?d;OJ`ss)B+qLGNm&C{lDW^BFKo_G|%HUepB4^HP2YYT?7 z5KMW%%ii278ve2fTirE`z0%%9AngOZ0|`hl#eRTMkkR2kQhH(k1LfL3^?xeRig`-K zZkk%79HH!I397nXdP`44$SIj>lq>)&ks39+^rm@HiId=odRm+On~#!N(;9E)s%nK_ zc9D&Gksq|`BUb|l*5bs&?Pq!!?H!reSSXiox~(-Qo<;+qhe`1#s4Vs;XrulS(T_@u zjJ_GBRTI$DAj6vSdT{V2Z_)Oq-lj)!!U*)i_AFbiLtj-E>&m-9waFB;0jk>_FWY{p z^|s!}YuCD6y(!Q8&YnWrBLf@OKXVUNphmTAiQK?iRdho>^IvuxoC8=5{Q7njsyVE5FuIw6jphv}t#a-G` z7>*25f6OpBO9%$ft+HJpqCjhaFq;O)(>uDN-`BB@jb?c&Zr4!NyJQCA!w9q+I_WF{ zF@f}u*8OrxTHFKwW%8Zrh}Iyql7r1%2d1j#53A#sOz8;x43?CWLAMLS775hX?3oQZ zlKs}o-fr9;#hw7U0FJZr$n?i1z;RJeG`&5)PD>Oq^w(;{e0vCKt+Kgtl%zF5W+UM1 zL1u=88zdps_~GIMJ)n`*_3OeL*1SQuUgepurJpUAGA#2AN1c zgU}2kER-_-0KjdnjCxOBYtCM+FR~>=d6?|=y7?V__?5k$Y#_px%!>!f^aUwWyxpCW6CDd^EWh^x45h0WMI9!+FS)&NK=>yCs(7$T_F^!j`_r4*wHn*Nz#*5dWcE1cr8-7Ay7} zzq!?l;JbdcSJ8|5Z-Hp z;Wx=GbKr@aDAkR|PRp5MyX)&dvU9sGw{58IW}=iVd+<3bclLw%&Q4}+beBVJ40Z}> zBo8Ca4}aO-jZ1VF;iV~ws4{V+0_S6+JR;x zy81K%M2<`kDcO_jY}Ur@$dqk-3=-}VJ2HHu+1UboL1UYXU{fBpSF~?&b|0OSE!E_2}Rxfjq{DP1}O2^v(RJSz3`PmsCRf_a%#1HwE8Bd3lb*m{;yuB<73qtpte zp7|sLEjXMR$**l=q+6d%Q`sZvcnqlGHj01{J`d2+H3xWpEY~ZyG?{aA8)n6^xiS=zcy<$NE)rlXODv(uC6w zGaLzR!i-D2?&A`(CrGn!31U?E=Hz>xc4{1nRM9m-RkXZ2j`$}S&2cFlGieR90*PS@ z#!ddG0VC|yba+z5vcuGUH^yDT*w3L~>CPrb&o92?7ocGJ@_0u5lnG3 zT=)AWPiJq|V*FY^m6)A|jh4_O2jVY_s4bHp$S>5ayqRr99j2qmL8d6pCAu&%Z_BHC z@iCXvvupA7Eiq{d^QZ^ut>2QJbAiMdz6BA9K|yRO@i67H_ZP0NS=M#;fKGh#*R>)lFfSr-#M1uceEQF!ZH1YIq9W+TYn^o~H6PxX|1=yOfnXR;)&?)((8`m=VWPsQM zlPsylzOeXOjfb#m9{0eH$1#A)pKZier|x+b>}_W#|Ql$or52y&12=BzRTqyDYS2VpxNT-QWE=T=vCJL zh5IF>-H@AAwsaOQlhg6LXcFD_mBJYwkgUSD*}OE%#w=e6nsk}kux^J9X$7SUi#Pqk zOg>*Z`;WWqcMWCV{se)V1hckXL~^LoijTDQkh|>R6gUBcJm9akkd?Ao*pzqc zaaPN429X4+e);r3Fi3Mp23B4AK5~*tLJMatIug~>U4OsQ0DqAvSf{mPPGjw2>rlQp z_W7KlVxl|EQMKcEW2}d%Cr-holm(Y7l4&O}D)F^BjYac2t9l6P03GORNZ7*aM%0#e zZRGgV2}|gfP~R+;CBxM+$v}^ReTp|IgCPDY4Nb=3l{Nh-j^e20yP&syEnTkLeg`Bd zDX(2gdPcRZDZyGim(HvS8Y^!~6KLfmW+$gd8^33G(1f7_c25ICG)^MG!6-39-0Os3 zp|ZaumBiuYGAHtMHsA_W5Y4mQZi-)yiR$tdX$>%tu%$u0YMIu&)aVE)DdS$lmeA&& z5fVPbpRR3kMFbqc{GAC*3!BOxP7ycoh1+Fs#>MRr05GkD1=JjQzqp-_^K|ejcm^B{ zFfr~!QoZ>LH>PbGU!RI=blvK+{@PUk{qb!PTF*oG45An>h9z$^L~VH9rP5J?)sUwr z>#Vw?FX%)Zv7Y3n zt55?b9~3ru7oL_@Eq#XQe#g$c?iM=$fMjBVNjQ#(N;4<(zz$425uJG+QoYemLbY1AuB4pQO^s60W4lqYS}ij zWk(vmLy%5TCiP@8ry3tbRnTb zR$cnEE=J0L78rFrf^C2ewhhQH6=6N#_Jxyq+bdkaW#lTob>(B})i2?wiphe>1fQXW z!{?fqR^SDHSdMMrbOXx0`{yi4u&Y25z&J`}!fa>!Cx~9j6VqZ0e2tXMF~bXoP`;m_ z%bUPcvvP}veiUIOlg_TZI)SsC1lqy;3Z4vq2%gWFN)wN7HNV*#Ty9Ge;jO8(Cp>=Q z|8QVNEv+x%+pkkPMn?@>iQaBK-Tw*7C7z7L3|=_78s6cwWmfj-Hr}PHtbDYNIp;Y4 zj+f;#;88Fd5QU)TZwAL*e;00aVLJ#zPM_@KZfN`j5w_faVhv+|Yt7)9{Nux_t3$u{ zfe`H%%~u9y$YoV;(IxM(m*uLS_T=SEqYrw}(!{9m`2KFm9SuK0o#|BV);6&seQc3! z9fEx%7imAf^a<8xkZ)h$?`$t!>N1P$?vC#+(Fwgn=YO~$6r?KTj z@h)`pTloTXjSt}=fjO(m>^{nNb|AEprz@HZ0$jV}d%(g2t^Ncd-r@u!OLxv}@sc^t z0`_cZ-9D68)EUhi-H-95kmwdZArCx|L-5Z>lzd&XR(azsu#0YlJwCGK-oVc)U#88W z6&@-CJS~n;Fo56W4m%(;#5`^yxUzxBmtJ`xY^V(7*7ATw>5)bmO zWey{QGNmxGy^-+M?AFxuXzg5hZ!bN%moOk-kE{ z{y5l~CWa{Y;Q#dS-EUM(<94=nFwGhzCzrYIo4B#9!(v z$Lahf)8w)F?n)Pxr2q+oM5FFCqK?VzOO+#~hcZvXiZqL+ET2c9zIn*0p zvF=kBr1$u@=7Z{$0cN|-(`4~((R=hFL{=5i64m?8xbTSFP^+qHzd1-F*(>}_)$hMG z5e)7j!Rn~|mirS_Ykkj0s~*fov6J}oN)J?FE7Ho-(_l?Bk2Hmy29LLNFH(Dp>k`4- zGJ^~0**5u&)gtXwW72hNoH1h;f-C(=jBLIEeeQ z#5p&3oye`Zd4yUvbOomPW)~DUM#!u@Fh0LGSzjvR%tSCm z#JJSt;{39kfLg|u<)HM)N73+!(rP56Wvf+HIr;L{PY?%$9?)TVq3|uMKJAe{@rA*? z_S?5jFvB`3J{qBD)i;Rw89@a(1h;At_;$fH4}ZN?5n+ zg+)#M)-M$nr9hj3squ@gfU)u6a~I3FWu8Jz`@LHdQBIRi7Z}UJza;Y>M^*hT-V8ny zk_jUNY&XBgx`TdMTrx%EUB<#T@EX(qlQHNa2!d&?eBqEc?xnszvZkzhVV+B1Kw{XQ1w>N^N6OWC8Ob?!7nFr8l$^!@hmPP zaw`45(ORX%Nru(fhiSzxTpJVg2y!5!Ys*S-WSGvwPA32Y8Q<;DasAInH-ygMY&JK- z`t-((>Dw)CtMw6%ub6(v$^NT z6)2$_5bpNaarVqfbi$!5k=61_j`UFf(%Yngj4b4-bud1Tj%JxofFmJ3C8W`{m#r`M^l73s3lFV+boxD$~LanV< zI={WCBSKL3F}9t5lv>^;D%xIIDVf#$?kXASrVgA{N}1_VYGGY2F<*qndy95jY4q(8 zjz-~ieh*Q@ml}v#oNBOz;_GV_lJ)dz{-!t#__XoHie@ftDQXAWcj|mBiotQ4lh+ry zq5bNOpI)w0t6{yABk6jK_b4*cqvpqujxnFlB#jEQ(6vfJ%L(}Jk}WMhm1BW}xu79r z=mp*oMhu7)C6?%d@L&9ye-<|O|G?1mCi3a1#5kSm=F^vagXD5!7aCQMi`lASq}#fK zUU`IuiG8G;=H}$6bNV3iK!H+(w`JMCBgwq{k2GBxLVS$D_&L{jS{m0q3b`reVXmzn z0Bt@cV*W=l=YQ7!9dU({e51|I3yAqZk-V4UT4Z?ZL9G0V(%yjoT|t_kAddnspc(mB zMByAu5$S?>KS9;gfRE7cDT(3Ly$4d40r?Bll8;1jL+zHSa5-1uzKQk$LFT5!eAk zD=PGY^o!2@^&m7+?%T6nQhl8+l_#Wk4V&b@(z`G=S$3w=op=)6o1by>;E>o>d>8Pt z3R&qM;Jt>cW%t5<2W#KpC=2TCoH;dXVaI%LCw9^Gcca(VX|(~bk6W7E7B(E8CvA7x{9#>S4uo_d-N2g+IMi zTOi8q7vZmYVHk9s#KwRp;U=vRm(ZyDZo3-L!fYA|I^0=3xi zT1&@7but&x#+gn@HczLeRp8wF?G5|_7GKdgLy~rni^QBcxVGS)IjfpytS9g@B^!SMQ*VI>p{o))6&p6 zIpAJ(2)tWK@;pg8ViZac&2CGAFT|o&w{qbg5jE2I@=^@-J^X!D3T(0+h9rNooEW@1 z+`_CsXT><9qF(>L{HqXF_oN*Q<{Ef|E^z*F4HD*8{F#)kwK~G6DLnm?zO10hux}6K z<4$>ETCoR{@qG2RGs_;bR9miytCrqsH%B)5|+5I+S};&lsAE% zcx;iVd&HMlf(Xq!iN005C8$%CU`;;I(B(I;(rssT6i>d9#&+;IX8Hd8;{oG^{(#h; zEjy&(8`UXHT6K>XBXT`N%>8x#+}5dvo$ic?3|URj_L}guvh$C})Uf@+l@=DXA<{6w z>y>Mk*0ecNH;XxXi23>8RxhE?sgQMho(1SD5`SkMJ}vq!V@qT5;Di`@`N`+gDs+;u z>FDJ_VtCVi$aG27fFcw?mR7fDb`3Az2Gha41D8@=W;$A^%O*JP>xh0-?@>L|rQ=Dr zbAa5OpeObR>Zo`$C33RE
f%eWf&=U8&|cd->(pxEp1P6o=t6N1!Ps=yET5-N&o z&WMZ4<(nzBOzCdd#^Vu#DmO1I&{6(vt0U*pH%T3;Ej( zja(P`*)>nL>k@3QuwWt=gj-v;zzQXMueIQd5jhF6Le~p<6iz|PI9#@Hz8PUIuD#6a znkd}0G|7;9Axf5a->{SOwlqYlv*tD@6V4L)<+b4}gaMI6Orhud%VwST!5t!MKu7Ru zayrBOTCMBN9JZM=WmCr?=Ho@r31G_Bhr^Ao4TCr0XN7y^Fec(|1Tf% zVI9hKzt!Oiy$CBqXc;+QxLdULQ|&czA5gdZ&>z&q7o{4iYBp6znyGQ`YCO7yb$BXF z7s$1HZ%O#GE*-h9tUd#@Vs4kt$@GKCZh{fCVGM@j^KeSryl6?uVUwe&_F)%7qwP-j zLmudpSotBn<+2{UAvCWmuueC)i+t>Vf&j10c0o5=j6YTFINe9`b;YjYt46{5ktlA|yzXmSxypTrRshAF$zcN67OI+a_CLFMAf+zFRH3A4Uq3P!4paGx70G`0GDMnn zkoMFPxr%^B=jM8z+WCKXT5chivq{nXY`#zly*Zu!-hKambt$HQ;ObHL&QghaL9T@d zbsvpK-0W2@dF1W#otN*ns|tV#CyVBJUojJH6vyKJZ8sMEv1^)|i3t}@`(%@<-rdAC zBjnPNbz21PQD0!^k7^(%Z7_golkH`T`t-RwQ_oFTz9Dk$bR(cK_Tg+8!J}>^s|xr&NH5CA`$f1Wl!^Py<1kDOoHBj_xMuX*pvdfPW`F<)puZqwkz(b3k-=Iowo z=e6rRhtHPO2mYG`K{uq~@8=guTG;V~_Ba2eKtBU(c1(PM6k7P4qkd{fl#eAT7m*^#g4UwDF#l z`~=OkVm`){dHnp{F$Anxf04ghY4UxKxLOu2pt^RM=ovp_K5a$JtQ=c}*T9 zF0I8Ov8^@k%U&m=G++FptoAEcJKW@V~Z~g=w49rsl_-7aVyc@VUlM!w>oth9r zF9%MW#Sc$&;kLWT;9F^Kn8RqIrO1<$y(su*8vST?>qzOV#+qnTF{Knw;xRgt0gyZ7 zZ!f+?MEc!LTA~r=F@DRO2z6-Ub*BDLjgPn-F9=T#=VK61D%5Cq8wan>7~E{EB#dHr z&s1wk+QAKJ_=G*#4xU~DUX8**KOIL4BJpmul30jD z^n;q=2)+J8KBI#dH^hoS_B%2l4}tniLG#hOaZe`pIG``dXN}b_Y$)h`@S55?A^1)D zOS;;&ob1a@6(M&$!vyE=c*N5`rp=?Etv(r#xcZ!Dc7HXZUsGV@c22p_>sKe_G0Q}x zn-b&)C*!9@d{SaH#9umWQp?*|_tQrU5WZqui>@8kDqO@fZn`SQI)gXHi`(ZGR|TTi#w}pV(HR zDiufKD{5SVG-#uk93aewgDr`rkzz1=mN1FO054-E$y>_mRX5WrBSTaPF90WxEZnRr z-GK#(5Y+35CA2LyJ2G$$Eq?JKpBi&Hkh8QVZ&IvbjbPYR0a&7Qw0C{h4*r`+3LoFa{yR3}qIwn1$<{4u~-(Uu`} ziSGN+F`Nw=t100c%46YPqpK2TfL8rrsLou9njRW=k%0fkll=VKq@Ct4-ADSrQ7&SY zQax)lm2p0P74uy2EtB=P+ZOE&8F;x_@3d_IViOKPiTX<`um1**#m@Arcu@(O-E$>R zx_Br`8PtUgcpx{A30}r>JW-Ahp3?*Np@a+l7sr6wak>1P@tRWGS6CF(A;q3y-%b?d z-}mT^-4#(^CKyeL%C*Sh)-CM?Sie11v2(8S8F9~J`cjKVQU;jwC=qGpCb6v8{LgPE zrIESV5Ro%0f6{$hlKtYKbB3{(iId2Pl``?Q>F8r+;gX=f_ItP!(v68D4RBG(KnAD) zNr}kBtj4f(om3~cUQhWjW8`CIUu>`is|xwFKX$szFB#3heeRFwLMLTMcLoV147UwZ z4U~{6h+DQ97^k!^?lOaU%mJ$dDm;6_d~Nl)GJROuQ_s#sA%uk_!88*sc^({#%v5dV z_43wgEJTWYuA~ur4ndKMsW)?D(#7_f&VL{(N=jTM95wcHi2W&wHI0?tW}C2ymc=fv zQ|9;QgsYG-kDb=Q*~7ZY1YdQ$r*|hya?*$#!P?hn7x5_eDz!+ur4`3q%1_f($gE@a za9q}NVh2=Lj0WGiTg8DD{`x}0d`qwD>9!Sbidq{eTPUA)Q|?(BIL8jxDpEnTV&qBP zZMDXymIK#|??5a{T`C4>r=kX)%e-SZI$q1wR-3S{PVF`7fj!gReuvwL)vk;+An<=vhL`!-lK*FJh{SsJiF&Yly zFETvq^oE!L6hHtn|237*9rtVH{gZzFm4@%bxv>-7i#aKZOG#Cl*2#(&?2lCilLV7E zUtL9o?X(PHpU2TqxXXVaB8rJG?KX1Rs-~59$Uz-3;&c{(@nOTP8 zzs%KkX#b=s@lQJ6|HyU20(y{SKS3)G@&M55F2>n*33}12xqS~aq%Ohs6V#&!1&|RA z^wvUK`iV#B1lLts{Uj2a6pW6f`z7Hh4#-ND_-{)81L1>+6?L9%k+k4{yuk+-*}5=o zB?JUPM|esTmYK0enSGpzzT78O|BeUHPp(I(m8(ubrC&`rSu?rAlLeZKi zE|w76*OO=gCVg3G(%Nu{ddg3byTYPiz8GyierYv8m89Ejd4vi(m{an-bdGO`!$i1S zH*jP2mVnFRv^ds~*Z~P?5vjH25o}1fAv;++3YR~^+Ibey;b}&GGDn8BNO#NU`rNdI zz{Oc8LJJ*4qPw{g^dML^js_$Wc(NUCba@5%YYrIRl_0XHX_%XDT$&MVE^Bb)t2yA@ zq<8FlCC8p~$UQ35O<7F9v`iP}#cNLci7B_OO@PsGCUyhg%8vpgTncB+AWF;`^I=D; zLd)0%@0eF0ANKeR*vNSgy1&|uJI)t#KQL52D2d2X$nAD7ntNudJ8F$1B-<80ok4PM z-vRa<(UPC#E4IG)evAR-h?iPme&(V&HN-5%`RZ*SSm5BxV@gT@TQKW_g67?p+iM1L zcdX^0F=?!+e(%+NZ)c=oEy)kjXyyz{(oy_C!4QJM>j?yq=Scpr`t~rPJjtJ+P`mLH zOQi;a9i_Cf zW~7W^hPZ!#-C;=~bbwNn5XqzBmKUz;mc$X9^uLrl%&nfQbEGSq=fSUic6m1xbZ*ez z-b#$&w74TsZSPL|5neZ|FSjb~Kh6Zgv+^J+AWuio1z)5^AsOI&5w`$ivzq#M#;Mk( z&PLd;Yq9(X6?TEHH4r||O%Q+v1zMp1tukTDE(R%_oBp<9m2``ZS+;}NKL`i^8Zk<9 z>{uDk?%`}FCQA3vEk@RgpQL15pzrEVzzGw~UPQn`9zY*&8&C@cT@~z?K zEbVgZ7>*&|yc-08-!5)6ul?1N_<3MU8J>J9Z2HUQ&hkNN=|%=oTvRtvh~rahl`RHt zYS-M@^YjGn^tLRZRBI=qLj4433tkkvYJBgX$pa3D_X^XSrW=`Bw*}s|V8sEqr_qk0 zIWnduAQ(Th2=Q`a578e{Wrt%feV50L=PxV*P}g2ye)_G zGl-(BY%Lb|JFNa7w*)5rE1S*7j zUTw&E3?58GrqLY?e#&9Erai+f6O4RJ$BljgUDgTk<#8j!IvnZ*i&}dw>z4*sZMzvo z=*;(oFkKfEo*n46Z;itYct32R`93UN5|QVNhkwBX3-sDNXv93)j}r74MGtqK34Wpd zk{SXb*gn@B9RvL@_P#SLsx`~H2ue^ua;8u~GKhd6sQ@L3Py_+VC`c3#$+18sN{)); zj3mjDa|X#dC&^Oef(m}e+kJcPo$2oBaC@fvoBqL5gu|ig6z6@{UVH7ex_?e9lL6Ao z2qi%j7r$K-3;SeDAaI8w5!f0 zqG#r1WAyv|S;OUeYg6!V)RS~9mKPQ|vQ7H)XIv{CoGPArmD0P!5Mg?rctHrf<&r+6 zUh1y|ttgXP7jwupLT^d|^?kOJ6b(9A`0h6idvfD8+vmi33&YjD3$sBpP3pCc5gERm zTY6gI!8!U{wYFvYGy1@gr%W?=EG6sYW`SEo+l*_76L&Jpqo5vJ(H5>3-EEniyD~+3 z9DuX6{i)A^`Fjtup^fS>6QXzT9$b&}zD*ATzpyIx;zm?{LF)Q(KLRXg zj?p@yq`+EB!9$Q{Al&2645FNEP+obO*Y11EraVTbb~D+;!Mj@csS(DVRdfSIUlZ6G zvL}|`Cy94N<9GIBKT1LGZ0d1jOM z(UTHaVEw$e9M}S6d%FpCUfU7#|CTthLlLD!K_)JKnZa3F%-3VGWG9g~BB(;Yh+QLa zprS^lxTfUQS6DIg`>LORzMWooL&ij>aD6i6T7r4RP{)SxbzPkRv| zUgz~OP=C5-L73X)=vMqu@)ecvi8BS(st5$<`X_{|XXfUSj8u)=Fl~ulS%{W_fL1e` zPI%JViKIXs9M&w>e%!9&JhP^nl({l$>J<%>>x~1Wn%~{T zz@R(y^^8u~x~=?-@$Q~6jn%ja>(o|*x2GKg`UQ9AR|LxewL*<)P6x$C?gtBx(luCf zNa97+k5#*GNg+bmv-zSxf5r@TIB!Ux&onDyaYXqo1%$B5L|h&oD77h)e>N+*7J@^H z9tXG9Y%pxph|=rww_-7I7ElDyYVy-vrGh?tv)uhY2geO5$yYI{?I9O{8ek1@ z;zcULiQk=`(&yBExV-XBTBKV+CSqBA3MRH=`MWBEV@E8+ijEPJee;f>iruI1Eg%oC z!kYbG0yJ5we^zz*m;}^;*0>^~Y$jSP?XJrO6(MBlrmy5o2xpmMWcy+Fi=gax7g*9@ z0mQHZz+qW_78*Za3jek+9*D%pQ3B2~IXZsC-olaEo=ROwv%!t3yEsQ--7r+I+qUI$d@Wv(&|D}dkPwg1y|nqxV~mp{c6@Vnb=#~z{$^&Ne~=B zO{&@e4Y;jxVQ73L1q1MDKOn%D0Xey<&=8$#ZP; zw$apJ#rJj;rAK&Wx^4RWe59#CM7FaSzkhofEL&EZk(j%@bhv1D?D+u5k&Zt=mh1h} z-ILKX*% z_}2LadOjirHQo7E-E;NZM+|}vCgOI5ilt^+a@w#uY-Xor23gHOtwx;>-J$UWmioRlIBhCZE+pW4Hm`Ek~@XN zYjc@QaSrmraZ%3CpR#||`!cpd6&0u+GKXF2e4dFEz3QR8xw5TrX{_j458#m3t@Xvd z`0=(rxpg%qt4Q%iOoxD=kIkuin>OR#s#2s1PdQm76m3>#i9JwFh3wMHcC~jD6(p(U z>W{wS7V1r;BT~#ui?t(tZ8O@hXqMY~(O7L7=&*$~{m51{=H1jD=_#634#$}si~ob^ zohB{d@%Hcf6&jjl4vV{*$=DBYg~_0DCKK~%~&R%wOxN5I%Dyu-^U4NS&cdZ zCu?NnPIr}#qjTS4V11~!O*6cJ1iNcPqs5hVztR-sdUxwlnqRJW!D!8Kk!8l?u^S|q zhWlgM!AvQ}66V*BzPP+Po`f@CvE#%T@6lFag=wDR$E#93? zFm7Ed0R%SoSjebbeU(n_Odjxf=1}`3a8uNVtNnv-{l9cc!hxs{9S`W;_e9=Lj(nm_ z-i+d$u?x%H!j^er9ZBHOWF@gGx^p7z5u&YAlUkNLFxXqNFyjw+br1d7)%G_WQ2k?n z=g^+cOZ7lLwaA)|B+!fA(^C|V)mKr+i%=DIXj{(QZp-WLgz2RK05G-H zh!~N(#D8s3Cd2adkUs8EZ`)iu(DE)Z@sdI@V3RVw1jU;}7)=~*JQ}|_R+%g>BfPu2 z(KmM)B)17-uwXbC0^u3{4u}5I0^u+Dobp$W3X?iN$$$mFgA7M6fPr@1u6MB7v11GW zZK}YVmR)%JBs;p}BUtM=jGPKv)`9ot7fA)ch*oTpTgA?&B%t%jf!apfn5N+<^bod2q4BYtfh*eEU-vCE z=2q=CeZoy9nV#UpS+F7G0Luoa?dpSDP>rXv8xLA{Ob+Sr`xb>v4s(F zhr`fn7hy>k^~|1vIh1jz=pa(p8;a*FC#gT&J8Lz01=g-GVA`~1 z0maOtrgx9k<($9|{*pJ~pY0fT>WBywbd7P~2@t<@roi>Sc&ELVw(;OvR3;n2PRRVI zm++-emuT|39%|skk5pjelefdT_Jjs*(#z6f(K3W;XQ>4RU=1ie#Kpm(sQ4@QWWYu= zGIw{j))rH_P5Bi}#d6#G9To}zN)jW2_>5LWb&5XfQP7YcRS~VS9YRoGq7GxwrFykA z^Q8%`UB6)UkwR-~GMWKX_x`=t57t=?f~ej;Jt?kkGXjS^jp?sPbH|q94d7KeecGv} zQg?SazL4tDpa9%Ru!LJkKOI(RL%Kc!O00=Fw|^XYZW$X4$$V{;;~< zdlSXo7vket0p4#`{S28B((w#>KNpENaM62O%s>K1if*uLlMb!e_S`l(6`rxQh-j@5 zwN2gQt$t&{B3vTkv?!`OBr4ryOP}iCMyI58av3q#SC?>3vNJ|O4!!&cvHvP)T0yV3T%MXM%k?8pE`0Z40;w4w=*#@!()atg zNN&YStV}Pb8x0eqKP!*(u&sYauD`*f1hPH#5Dbh4`2vc98|4Y#CL)3%YY@Pf91FOi z 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
    S1auQs;Pe=I2rSro7M!4&cwJqJw~#(a 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 + +原理介绍:作者主要使用了以下优化方法 + +1. Warmup,在训练一开始让学习率逐渐升高后再开始下降,有利于梯度下降时找到更优的参数。 +2. Random erasing augmentation,随机区域擦除,增强模型的泛化性。 +3. Label smoothing,标签平滑,增强模型的泛化性。 +4. Last stride=1,取消特征提取模块的最后一个stage的下采样,增大输出特征图的分辨率来保留更多细节,增强模型的分类能力。 +5. BNNeck,特征向量输入分类头之前先经过BNNeck,让特征向量变成正态分布形式,减少了同时优化ID Loss和TripLetLoss的难度。 +6. Center loss,给每个类别一个可学习的聚类中心特征,训练时让类内特征靠近聚类中心,减少类内差异,增大类间差异。 +7. Reranking,在检索时考虑检索图像的近邻候选对象是否同时含有检索目标,以此来优化距离矩阵,最终提升检索精度。 + +#### 2.2a 快速体验 + +快速体验章节主要以`softmax_triplet_with_center.yaml`配置和训练好的模型文件为例,在 Market1501 数据集上进行测试。 + +1. 下载[Market-1501-v15.09.15.zip](https://pan.baidu.com/s/1ntIi2Op?_at_=1654142245770)数据集,解压到`PaddleClas/dataset/`下,并组织成以下文件结构: + + ```shell + PaddleClas/dataset/market1501 + └── Market-1501-v15.09.15/ + ├── bounding_box_test/ + ├── bounding_box_train/ + ├── gt_bbox/ + ├── gt_query/ + ├── query/ + ├── generate_anno.py + ├── bounding_box_test.txt + ├── bounding_box_train.txt + ├── query.txt + └── readme.txt + ``` + +2. 下载 [reid_strong_baseline_softmax_with_center.epoch_120.pdparams](reid_strong_baseline_softmax_with_center.epoch_120.pdparams) 到 `PaddleClas/pretrained_models` 文件夹中 + + ```shell + cd PaddleClas + mkdir pretrained_models + cd pretrained_models + wget https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/reid_strong_baseline_softmax_with_center.epoch_120.pdparams + cd .. + ``` + +3. 使用下载好的 `softmax_triplet_with_center.pdparams` 在 Market1501 数据集上进行测试 + + ```shell + python3.7 tools/eval.py \ + -c ppcls/configs/reid/strong_baseline/baseline.yaml \ + -o Global.pretrained_model="pretrained_models/reid_strong_baseline_softmax_with_center.epoch_120" + ``` + +4. 查看输出结果 + + ```log + ... + [2022/06/02 03:08:07] ppcls INFO: gallery feature calculation process: [0/125] + [2022/06/02 03:08:11] ppcls INFO: gallery feature calculation process: [20/125] + [2022/06/02 03:08:15] ppcls INFO: gallery feature calculation process: [40/125] + [2022/06/02 03:08:19] ppcls INFO: gallery feature calculation process: [60/125] + [2022/06/02 03:08:23] ppcls INFO: gallery feature calculation process: [80/125] + [2022/06/02 03:08:27] ppcls INFO: gallery feature calculation process: [100/125] + [2022/06/02 03:08:31] ppcls INFO: gallery feature calculation process: [120/125] + [2022/06/02 03:08:32] ppcls INFO: Build gallery done, all feat shape: [15913, 2048], begin to eval.. + [2022/06/02 03:08:33] ppcls INFO: query feature calculation process: [0/27] + [2022/06/02 03:08:36] ppcls INFO: query feature calculation process: [20/27] + [2022/06/02 03:08:38] ppcls INFO: Build query done, all feat shape: [3368, 2048], begin to eval.. + [2022/06/02 03:08:38] ppcls INFO: re_ranking=False + [2022/06/02 03:08:39] ppcls INFO: [Eval][Epoch 0][Avg]recall1: 0.94270, recall5: 0.98189, mAP: 0.85799 + ``` + + 可以看到我们提供的 `reid_strong_baseline_softmax_with_center.epoch_120.pdparams` 模型在 Market1501 数据集上的指标为recall@1=0.94270,recall@5=0.98189,mAP=0.85799 + +#### 2.2b 模型训练/推理等 + +- 模型训练 + + 1. 下载[Market-1501-v15.09.15.zip](https://pan.baidu.com/s/1ntIi2Op?_at_=1654142245770)数据集,解压到`PaddleClas/dataset/`下,并组织成以下文件结构: + + ```shell + PaddleClas/dataset/market1501 + └── Market-1501-v15.09.15/ + ├── bounding_box_test/ + ├── bounding_box_train/ + ├── gt_bbox/ + ├── gt_query/ + ├── query/ + ├── generate_anno.py + ├── bounding_box_test.txt + ├── bounding_box_train.txt + ├── query.txt + └── readme.txt + ``` + + 2. 执行以下命令开始训练 + + ```shell + python3.7 tools/train.py -c ./ppcls/configs/reid/strong_baseline/softmax_triplet_with_center.yaml + ``` + + 注:单卡训练大约需要1个小时。 + +- 模型测试 + + 假设需要测试的模型文件路径为 `./output/RecModel/latest.pdparams` ,执行下述命令即可进行测试 + + ```shell + python3.7 tools/eval.py \ + -c ./ppcls/configs/reid/strong_baseline/softmax_triplet_with_center.yaml \ + -o Global.pretrained_model="./output/RecModel/latest" + ``` + + 注:`pretrained_model` 后填入的地址不需要加 `.pdparams` 后缀,在程序运行时会自动补上。 + +- 模型推理 + + 1. 下载 inference 模型并解压:[reid_srong_baseline_softmax_with_center.tar](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/reid_srong_baseline_softmax_with_center.tar) + + ```shell + cd PaddleClas/deploy + wget https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/reid_srong_baseline_softmax_with_center.tar + tar xf reid_srong_baseline_softmax_with_center.tar + ``` + + 2. 修改 `PaddleClas/deploy/configs/inference_rec.yaml`。将 `infer_imgs:` 后的字段改为 Market1501 中 query 文件夹下的任意一张图片;将 `rec_inference_model_dir:` 后的字段改为解压出来的 reid_srong_baseline_softmax_with_center 文件夹路径;将 `transform_ops` 字段下的预处理配置改为 `softmax_triplet_with_center.yaml` 中`Eval.Query.dataset` 下的预处理配置。如下所示 + + ```yaml + Global: + infer_imgs: "../dataset/market1501/Market-1501-v15.09.15/query/0294_c1s1_066631_00.jpg" + rec_inference_model_dir: "./reid_srong_baseline_softmax_with_center" + batch_size: 1 + use_gpu: False + enable_mkldnn: True + cpu_num_threads: 10 + enable_benchmark: True + use_fp16: False + ir_optim: True + use_tensorrt: False + gpu_mem: 8000 + enable_profile: False + + RecPreProcess: + transform_ops: + - ResizeImage: + size: [128, 256] + return_numpy: False + interpolation: 'bilinear' + backend: "pil" + - ToTensor: + - Normalize: + mean: [0.485, 0.456, 0.406] + std: [0.229, 0.224, 0.225] + + RecPostProcess: null + ``` + + 3. 执行推理命令 + + ```shell + python3.7 python/predict_rec.py -c ./configs/inference_rec.yaml + ``` + + 4. 查看输出结果,实际结果为一个长度2048的向量,表示输入图片经过模型转换后得到的特征向量 + + ```shell + 0294_c1s1_066631_00.jpg: [ 0.01806974 0.00476423 -0.00508293 ... 0.03925538 0.00377574 + -0.00849029] + ``` + +### 3. 总结 + +#### 3.1 方法总结、对比等 + +以下表格总结了我们提供的ReID strong-baseline的3种配置在 Market1501 数据集上的精度指标, + +| 配置文件 | recall@1 | mAP | 参考recall@1 | 参考mAP | +| ------------------------ | -------- | ----- | ------------ | ------- | +| baseline.yaml | 88.21 | 74.12 | 87.7 | 74.0 | +| softmax.yaml | 94.18 | 85.76 | 94.1 | 85.7 | +| softmax_with_center.yaml | 94.19 | 85.80 | 94.1 | 85.7 | + +注:上述参考指标由使用作者开源的代码在我们的设备上训练多次得到,由于系统环境、torch版本、CUDA版本不同等原因,与作者提供的指标可能存在略微差异。 + +#### 3.2 使用建议/FAQ + +Market1501 数据集比较小,可以尝试训练多次取最高精度。 + +#### 4 参考资料 + +1. [Bag of Tricks and A Strong Baseline for Deep Person Re-identification](https://openaccess.thecvf.com/content_CVPRW_2019/papers/TRMTMCT/Luo_Bag_of_Tricks_and_a_Strong_Baseline_for_Deep_Person_CVPRW_2019_paper.pdf) +2. [michuanhaohao/reid-strong-baseline: Bag of Tricks and A Strong Baseline for Deep Person Re-identification (github.com)](https://github.com/michuanhaohao/reid-strong-baseline) +3. [行人重识别数据集之 Market1501 数据集_star_function的博客-CSDN博客_market1501数据集](https://blog.csdn.net/qq_39220334/article/details/121470106) From d3c4b46eb110261bfa6e4dbaa13c35cab08fcb45 Mon Sep 17 00:00:00 2001 From: HydrogenSulfate <490868991@qq.com> Date: Wed, 8 Jun 2022 18:29:58 +0800 Subject: [PATCH 2/9] polish reid doc --- docs/images/reid/reid_overview.jpg | Bin 0 -> 89454 bytes docs/zh_CN/algorithm_introduction/reid.md | 86 +++++++++++++--------- 2 files changed, 51 insertions(+), 35 deletions(-) create mode 100644 docs/images/reid/reid_overview.jpg diff --git a/docs/images/reid/reid_overview.jpg b/docs/images/reid/reid_overview.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2562a529b537113b7b7a1ab65a4528a23b8bd8d3 GIT binary patch literal 89454 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 p|OHZaal4?mMJYGxmm$#>PE=s~zyJ!6bXr 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 -以往的行人重识别方法通过特征提取模块来提取图片的全局或多粒度特征,再经过融合模块得到一个高维的特征向量。在训练时使用分类头将该特征向量映射成属于每个类别的概率从而以分类任务的方式来优化整个模型;在测试或推理时直接将高维的特征向量作为图片描述子在检索库中进行检索,以得到检索结果。而ReID strong-baseline算法则是提出了多个有效优化训练与检索的方法来提升整体模型性能。 +### 2. ReID算法 -#### 2.1 ReID strong-baseline算法原理 +#### 2.1a ReID strong-baseline算法 论文出处:[Bag of Tricks and A Strong Baseline for Deep Person Re-identification](https://openaccess.thecvf.com/content_CVPRW_2019/papers/TRMTMCT/Luo_Bag_of_Tricks_and_a_Strong_Baseline_for_Deep_Person_CVPRW_2019_paper.pdf) -原理介绍:作者主要使用了以下优化方法 +原理介绍:作者以普遍使用的基于 ResNet50 的行人重识别方法为基础,探索并总结了以下几种有效且适用性较强的优化方法,大幅度提高了在多个行人重识别数据集上的指标。 -1. Warmup,在训练一开始让学习率逐渐升高后再开始下降,有利于梯度下降时找到更优的参数。 -2. Random erasing augmentation,随机区域擦除,增强模型的泛化性。 -3. Label smoothing,标签平滑,增强模型的泛化性。 -4. Last stride=1,取消特征提取模块的最后一个stage的下采样,增大输出特征图的分辨率来保留更多细节,增强模型的分类能力。 -5. BNNeck,特征向量输入分类头之前先经过BNNeck,让特征向量变成正态分布形式,减少了同时优化ID Loss和TripLetLoss的难度。 -6. Center loss,给每个类别一个可学习的聚类中心特征,训练时让类内特征靠近聚类中心,减少类内差异,增大类间差异。 -7. Reranking,在检索时考虑检索图像的近邻候选对象是否同时含有检索目标,以此来优化距离矩阵,最终提升检索精度。 +1. Warmup:在训练一开始让学习率从一个较小值逐渐升高后再开始下降,有利于梯度下降优化时的稳定性,从而找到更优的参数模型。 +2. Random erasing augmentation:随机区域擦除,通过数据增强来提升模型的泛化能力。 +3. Label smoothing:标签平滑,提升模型的泛化能力。 +4. Last stride=1:设定特征提取模块的最后一个stage的下采样为1,增大输出特征图的分辨率来保留更多细节,提升模型的分类能力。 +5. BNNeck:特征向量输入分类头之前先经过BNNeck,让特征在超球体表面服从正态分布,减少了同时优化IDLoss和TripLetLoss的难度。 +6. Center loss:给每个类别一个可学习的聚类中心,训练时让类内特征靠近聚类中心,减少类内差异,增大类间差异。 +7. Reranking:在检索时考虑查询图像的近邻候选对象,根据候选对象的近邻图像的是否也含有查询图像的情况来优化距离矩阵,最终提升检索精度。 -#### 2.2a 快速体验 +#### 2.1b 快速体验 快速体验章节主要以`softmax_triplet_with_center.yaml`配置和训练好的模型文件为例,在 Market1501 数据集上进行测试。 @@ -34,16 +48,16 @@ ```shell PaddleClas/dataset/market1501 └── Market-1501-v15.09.15/ - ├── bounding_box_test/ - ├── bounding_box_train/ - ├── gt_bbox/ - ├── gt_query/ - ├── query/ - ├── generate_anno.py - ├── bounding_box_test.txt - ├── bounding_box_train.txt - ├── query.txt - └── readme.txt + ├── bounding_box_test/ + ├── bounding_box_train/ + ├── gt_bbox/ + ├── gt_query/ + ├── query/ + ├── generate_anno.py + ├── bounding_box_test.txt + ├── bounding_box_train.txt + ├── query.txt + └── readme.txt ``` 2. 下载 [reid_strong_baseline_softmax_with_center.epoch_120.pdparams](reid_strong_baseline_softmax_with_center.epoch_120.pdparams) 到 `PaddleClas/pretrained_models` 文件夹中 @@ -60,7 +74,7 @@ ```shell python3.7 tools/eval.py \ - -c ppcls/configs/reid/strong_baseline/baseline.yaml \ + -c ppcls/configs/reid/strong_baseline/softmax_triplet_with_center.yaml \ -o Global.pretrained_model="pretrained_models/reid_strong_baseline_softmax_with_center.epoch_120" ``` @@ -85,7 +99,7 @@ 可以看到我们提供的 `reid_strong_baseline_softmax_with_center.epoch_120.pdparams` 模型在 Market1501 数据集上的指标为recall@1=0.94270,recall@5=0.98189,mAP=0.85799 -#### 2.2b 模型训练/推理等 +#### 2.2c 模型训练/推理等 - 模型训练 @@ -94,16 +108,16 @@ ```shell PaddleClas/dataset/market1501 └── Market-1501-v15.09.15/ - ├── bounding_box_test/ - ├── bounding_box_train/ - ├── gt_bbox/ - ├── gt_query/ - ├── query/ - ├── generate_anno.py - ├── bounding_box_test.txt - ├── bounding_box_train.txt - ├── query.txt - └── readme.txt + ├── bounding_box_test/ + ├── bounding_box_train/ + ├── gt_bbox/ + ├── gt_query/ + ├── query/ + ├── generate_anno.py + ├── bounding_box_test.txt + ├── bounding_box_train.txt + ├── query.txt + └── readme.txt ``` 2. 执行以下命令开始训练 @@ -136,7 +150,7 @@ tar xf reid_srong_baseline_softmax_with_center.tar ``` - 2. 修改 `PaddleClas/deploy/configs/inference_rec.yaml`。将 `infer_imgs:` 后的字段改为 Market1501 中 query 文件夹下的任意一张图片;将 `rec_inference_model_dir:` 后的字段改为解压出来的 reid_srong_baseline_softmax_with_center 文件夹路径;将 `transform_ops` 字段下的预处理配置改为 `softmax_triplet_with_center.yaml` 中`Eval.Query.dataset` 下的预处理配置。如下所示 + 2. 修改 `PaddleClas/deploy/configs/inference_rec.yaml`。将 `infer_imgs:` 后的字段改为 Market1501 中 query 文件夹下的任意一张图片路径(下方代码使用的是`0294_c1s1_066631_00.jpg`图片路径);将 `rec_inference_model_dir:` 后的字段改为解压出来的 reid_srong_baseline_softmax_with_center 文件夹路径;将 `transform_ops` 字段下的预处理配置改为 `softmax_triplet_with_center.yaml` 中`Eval.Query.dataset` 下的预处理配置。如下所示 ```yaml Global: @@ -180,6 +194,7 @@ 0294_c1s1_066631_00.jpg: [ 0.01806974 0.00476423 -0.00508293 ... 0.03925538 0.00377574 -0.00849029] ``` + 推理时的输出向量储存在[predict_rec.py](../../../deploy/python/predict_rec.py#L134-L135)的`result_dict`变量中。 ### 3. 总结 @@ -204,3 +219,4 @@ Market1501 数据集比较小,可以尝试训练多次取最高精度。 1. [Bag of Tricks and A Strong Baseline for Deep Person Re-identification](https://openaccess.thecvf.com/content_CVPRW_2019/papers/TRMTMCT/Luo_Bag_of_Tricks_and_a_Strong_Baseline_for_Deep_Person_CVPRW_2019_paper.pdf) 2. [michuanhaohao/reid-strong-baseline: Bag of Tricks and A Strong Baseline for Deep Person Re-identification (github.com)](https://github.com/michuanhaohao/reid-strong-baseline) 3. [行人重识别数据集之 Market1501 数据集_star_function的博客-CSDN博客_market1501数据集](https://blog.csdn.net/qq_39220334/article/details/121470106) +4. [Deep Learning for Person Re-identification:A Survey and Outlook](https://arxiv.org/abs/2001.04193) From 458fd345d37f30edc63ff4da38ff32598893710c Mon Sep 17 00:00:00 2001 From: HydrogenSulfate <490868991@qq.com> Date: Wed, 8 Jun 2022 21:44:45 +0800 Subject: [PATCH 3/9] polish reid doc --- deploy/python/preprocess.py | 47 ++- docs/zh_CN/algorithm_introduction/reid.md | 347 +++++++++--------- .../reid/strong_baseline/baseline.yaml | 60 +-- .../reid/strong_baseline/softmax_triplet.yaml | 72 ++-- .../softmax_triplet_with_center.yaml | 72 ++-- 5 files changed, 313 insertions(+), 285 deletions(-) diff --git a/deploy/python/preprocess.py b/deploy/python/preprocess.py index 1da32ad6e..aa66492a3 100644 --- a/deploy/python/preprocess.py +++ b/deploy/python/preprocess.py @@ -27,6 +27,7 @@ import cv2 import numpy as np import importlib from PIL import Image +from paddle.vision.transforms import ToTensor, Normalize from python.det_preprocess import DetNormalizeImage, DetPadStride, DetPermute, DetResize @@ -53,13 +54,14 @@ def create_operators(params): class UnifiedResize(object): - def __init__(self, interpolation=None, backend="cv2"): + def __init__(self, interpolation=None, backend="cv2", return_numpy=True): _cv2_interp_from_str = { 'nearest': cv2.INTER_NEAREST, 'bilinear': cv2.INTER_LINEAR, 'area': cv2.INTER_AREA, 'bicubic': cv2.INTER_CUBIC, - 'lanczos': cv2.INTER_LANCZOS4 + 'lanczos': cv2.INTER_LANCZOS4, + 'random': (cv2.INTER_LINEAR, cv2.INTER_CUBIC) } _pil_interp_from_str = { 'nearest': Image.NEAREST, @@ -67,13 +69,26 @@ class UnifiedResize(object): 'bicubic': Image.BICUBIC, 'box': Image.BOX, 'lanczos': Image.LANCZOS, - 'hamming': Image.HAMMING + 'hamming': Image.HAMMING, + 'random': (Image.BILINEAR, Image.BICUBIC) } - def _pil_resize(src, size, resample): - pil_img = Image.fromarray(src) + def _cv2_resize(src, size, resample): + if isinstance(resample, tuple): + resample = random.choice(resample) + return cv2.resize(src, size, interpolation=resample) + + def _pil_resize(src, size, resample, return_numpy=True): + if isinstance(resample, tuple): + resample = random.choice(resample) + if isinstance(src, np.ndarray): + pil_img = Image.fromarray(src) + else: + pil_img = src pil_img = pil_img.resize(size, resample) - return np.asarray(pil_img) + if return_numpy: + return np.asarray(pil_img) + return pil_img if backend.lower() == "cv2": if isinstance(interpolation, str): @@ -81,11 +96,12 @@ class UnifiedResize(object): # compatible with opencv < version 4.4.0 elif interpolation is None: interpolation = cv2.INTER_LINEAR - self.resize_func = partial(cv2.resize, interpolation=interpolation) + self.resize_func = partial(_cv2_resize, resample=interpolation) elif backend.lower() == "pil": if isinstance(interpolation, str): interpolation = _pil_interp_from_str[interpolation.lower()] - self.resize_func = partial(_pil_resize, resample=interpolation) + self.resize_func = partial( + _pil_resize, resample=interpolation, return_numpy=return_numpy) else: logger.warning( f"The backend of Resize only support \"cv2\" or \"PIL\". \"f{backend}\" is unavailable. Use \"cv2\" instead." @@ -93,6 +109,8 @@ class UnifiedResize(object): self.resize_func = cv2.resize def __call__(self, src, size): + if isinstance(size, list): + size = tuple(size) return self.resize_func(src, size) @@ -137,7 +155,8 @@ class ResizeImage(object): size=None, resize_short=None, interpolation=None, - backend="cv2"): + backend="cv2", + return_numpy=True): if resize_short is not None and resize_short > 0: self.resize_short = resize_short self.w = None @@ -151,10 +170,16 @@ class ResizeImage(object): 'both 'size' and 'resize_short' are None") self._resize_func = UnifiedResize( - interpolation=interpolation, backend=backend) + interpolation=interpolation, + backend=backend, + return_numpy=return_numpy) def __call__(self, img): - img_h, img_w = img.shape[:2] + if isinstance(img, np.ndarray): + img_h, img_w = img.shape[:2] + else: + img_w, img_h = img.size + if self.resize_short is not None: percent = float(self.resize_short) / min(img_w, img_h) w = int(round(img_w * percent)) diff --git a/docs/zh_CN/algorithm_introduction/reid.md b/docs/zh_CN/algorithm_introduction/reid.md index 90ec1bee8..cc2df67f9 100644 --- a/docs/zh_CN/algorithm_introduction/reid.md +++ b/docs/zh_CN/algorithm_introduction/reid.md @@ -3,16 +3,20 @@ ## 目录 -- [ReID行人重识别](#reid行人重识别) - [1. 算法/应用场景简介](#1-算法应用场景简介) - [2. ReID算法](#2-reid算法) - - [2.1 ReID strong-baseline算法](#21-reid-strong-baseline算法) - - [2.2a 快速体验](#22a-快速体验) - - [2.2b 模型训练/推理等](#22b-模型训练推理等) + - [2.1 ReID strong-baseline](#21-reid-strong-baseline) + - [2.1.1 原理介绍](#211-原理介绍) + - [2.1.1 数据准备](#211-数据准备) + - [2.1.2 模型训练](#212-模型训练) + - [2.1.3 模型评估](#213-模型评估) + - [2.1.3 模型推理](#213-模型推理) + - [2.1.3.1 模型导出](#2131-模型导出) + - [2.1.3.2 模型推理](#2132-模型推理) - [3. 总结](#3-总结) - - [3.1 方法总结、对比等](#31-方法总结对比等) + - [3.1 方法总结与对比](#31-方法总结与对比) - [3.2 使用建议/FAQ](#32-使用建议faq) - - [4 参考资料](#4-参考资料) + - [4 参考资料](#4-参考资料) ### 1. 算法/应用场景简介 @@ -23,13 +27,15 @@ ### 2. ReID算法 -#### 2.1a ReID strong-baseline算法 +#### 2.1 ReID strong-baseline 论文出处:[Bag of Tricks and A Strong Baseline for Deep Person Re-identification](https://openaccess.thecvf.com/content_CVPRW_2019/papers/TRMTMCT/Luo_Bag_of_Tricks_and_a_Strong_Baseline_for_Deep_Person_CVPRW_2019_paper.pdf) -原理介绍:作者以普遍使用的基于 ResNet50 的行人重识别方法为基础,探索并总结了以下几种有效且适用性较强的优化方法,大幅度提高了在多个行人重识别数据集上的指标。 +##### 2.1.1 原理介绍 + +作者以普遍使用的基于 ResNet50 的行人重识别模型为基础,探索并总结了以下几种有效且适用性较强的优化方法,大幅度提高了在多个行人重识别数据集上的指标。 1. Warmup:在训练一开始让学习率从一个较小值逐渐升高后再开始下降,有利于梯度下降优化时的稳定性,从而找到更优的参数模型。 2. Random erasing augmentation:随机区域擦除,通过数据增强来提升模型的泛化能力。 @@ -39,168 +45,7 @@ 6. Center loss:给每个类别一个可学习的聚类中心,训练时让类内特征靠近聚类中心,减少类内差异,增大类间差异。 7. Reranking:在检索时考虑查询图像的近邻候选对象,根据候选对象的近邻图像的是否也含有查询图像的情况来优化距离矩阵,最终提升检索精度。 -#### 2.1b 快速体验 - -快速体验章节主要以`softmax_triplet_with_center.yaml`配置和训练好的模型文件为例,在 Market1501 数据集上进行测试。 - -1. 下载[Market-1501-v15.09.15.zip](https://pan.baidu.com/s/1ntIi2Op?_at_=1654142245770)数据集,解压到`PaddleClas/dataset/`下,并组织成以下文件结构: - - ```shell - PaddleClas/dataset/market1501 - └── Market-1501-v15.09.15/ - ├── bounding_box_test/ - ├── bounding_box_train/ - ├── gt_bbox/ - ├── gt_query/ - ├── query/ - ├── generate_anno.py - ├── bounding_box_test.txt - ├── bounding_box_train.txt - ├── query.txt - └── readme.txt - ``` - -2. 下载 [reid_strong_baseline_softmax_with_center.epoch_120.pdparams](reid_strong_baseline_softmax_with_center.epoch_120.pdparams) 到 `PaddleClas/pretrained_models` 文件夹中 - - ```shell - cd PaddleClas - mkdir pretrained_models - cd pretrained_models - wget https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/reid_strong_baseline_softmax_with_center.epoch_120.pdparams - cd .. - ``` - -3. 使用下载好的 `softmax_triplet_with_center.pdparams` 在 Market1501 数据集上进行测试 - - ```shell - python3.7 tools/eval.py \ - -c ppcls/configs/reid/strong_baseline/softmax_triplet_with_center.yaml \ - -o Global.pretrained_model="pretrained_models/reid_strong_baseline_softmax_with_center.epoch_120" - ``` - -4. 查看输出结果 - - ```log - ... - [2022/06/02 03:08:07] ppcls INFO: gallery feature calculation process: [0/125] - [2022/06/02 03:08:11] ppcls INFO: gallery feature calculation process: [20/125] - [2022/06/02 03:08:15] ppcls INFO: gallery feature calculation process: [40/125] - [2022/06/02 03:08:19] ppcls INFO: gallery feature calculation process: [60/125] - [2022/06/02 03:08:23] ppcls INFO: gallery feature calculation process: [80/125] - [2022/06/02 03:08:27] ppcls INFO: gallery feature calculation process: [100/125] - [2022/06/02 03:08:31] ppcls INFO: gallery feature calculation process: [120/125] - [2022/06/02 03:08:32] ppcls INFO: Build gallery done, all feat shape: [15913, 2048], begin to eval.. - [2022/06/02 03:08:33] ppcls INFO: query feature calculation process: [0/27] - [2022/06/02 03:08:36] ppcls INFO: query feature calculation process: [20/27] - [2022/06/02 03:08:38] ppcls INFO: Build query done, all feat shape: [3368, 2048], begin to eval.. - [2022/06/02 03:08:38] ppcls INFO: re_ranking=False - [2022/06/02 03:08:39] ppcls INFO: [Eval][Epoch 0][Avg]recall1: 0.94270, recall5: 0.98189, mAP: 0.85799 - ``` - - 可以看到我们提供的 `reid_strong_baseline_softmax_with_center.epoch_120.pdparams` 模型在 Market1501 数据集上的指标为recall@1=0.94270,recall@5=0.98189,mAP=0.85799 - -#### 2.2c 模型训练/推理等 - -- 模型训练 - - 1. 下载[Market-1501-v15.09.15.zip](https://pan.baidu.com/s/1ntIi2Op?_at_=1654142245770)数据集,解压到`PaddleClas/dataset/`下,并组织成以下文件结构: - - ```shell - PaddleClas/dataset/market1501 - └── Market-1501-v15.09.15/ - ├── bounding_box_test/ - ├── bounding_box_train/ - ├── gt_bbox/ - ├── gt_query/ - ├── query/ - ├── generate_anno.py - ├── bounding_box_test.txt - ├── bounding_box_train.txt - ├── query.txt - └── readme.txt - ``` - - 2. 执行以下命令开始训练 - - ```shell - python3.7 tools/train.py -c ./ppcls/configs/reid/strong_baseline/softmax_triplet_with_center.yaml - ``` - - 注:单卡训练大约需要1个小时。 - -- 模型测试 - - 假设需要测试的模型文件路径为 `./output/RecModel/latest.pdparams` ,执行下述命令即可进行测试 - - ```shell - python3.7 tools/eval.py \ - -c ./ppcls/configs/reid/strong_baseline/softmax_triplet_with_center.yaml \ - -o Global.pretrained_model="./output/RecModel/latest" - ``` - - 注:`pretrained_model` 后填入的地址不需要加 `.pdparams` 后缀,在程序运行时会自动补上。 - -- 模型推理 - - 1. 下载 inference 模型并解压:[reid_srong_baseline_softmax_with_center.tar](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/reid_srong_baseline_softmax_with_center.tar) - - ```shell - cd PaddleClas/deploy - wget https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/reid_srong_baseline_softmax_with_center.tar - tar xf reid_srong_baseline_softmax_with_center.tar - ``` - - 2. 修改 `PaddleClas/deploy/configs/inference_rec.yaml`。将 `infer_imgs:` 后的字段改为 Market1501 中 query 文件夹下的任意一张图片路径(下方代码使用的是`0294_c1s1_066631_00.jpg`图片路径);将 `rec_inference_model_dir:` 后的字段改为解压出来的 reid_srong_baseline_softmax_with_center 文件夹路径;将 `transform_ops` 字段下的预处理配置改为 `softmax_triplet_with_center.yaml` 中`Eval.Query.dataset` 下的预处理配置。如下所示 - - ```yaml - Global: - infer_imgs: "../dataset/market1501/Market-1501-v15.09.15/query/0294_c1s1_066631_00.jpg" - rec_inference_model_dir: "./reid_srong_baseline_softmax_with_center" - batch_size: 1 - use_gpu: False - enable_mkldnn: True - cpu_num_threads: 10 - enable_benchmark: True - use_fp16: False - ir_optim: True - use_tensorrt: False - gpu_mem: 8000 - enable_profile: False - - RecPreProcess: - transform_ops: - - ResizeImage: - size: [128, 256] - return_numpy: False - interpolation: 'bilinear' - backend: "pil" - - ToTensor: - - Normalize: - mean: [0.485, 0.456, 0.406] - std: [0.229, 0.224, 0.225] - - RecPostProcess: null - ``` - - 3. 执行推理命令 - - ```shell - python3.7 python/predict_rec.py -c ./configs/inference_rec.yaml - ``` - - 4. 查看输出结果,实际结果为一个长度2048的向量,表示输入图片经过模型转换后得到的特征向量 - - ```shell - 0294_c1s1_066631_00.jpg: [ 0.01806974 0.00476423 -0.00508293 ... 0.03925538 0.00377574 - -0.00849029] - ``` - 推理时的输出向量储存在[predict_rec.py](../../../deploy/python/predict_rec.py#L134-L135)的`result_dict`变量中。 - -### 3. 总结 - -#### 3.1 方法总结、对比等 - -以下表格总结了我们提供的ReID strong-baseline的3种配置在 Market1501 数据集上的精度指标, +以下表格总结了复现的ReID strong-baseline的3种配置在 Market1501 数据集上的精度指标, | 配置文件 | recall@1 | mAP | 参考recall@1 | 参考mAP | | ------------------------ | -------- | ----- | ------------ | ------- | @@ -210,13 +55,171 @@ 注:上述参考指标由使用作者开源的代码在我们的设备上训练多次得到,由于系统环境、torch版本、CUDA版本不同等原因,与作者提供的指标可能存在略微差异。 +接下来主要以`softmax_triplet_with_center.yaml`配置和训练好的模型文件为例,展示在 Market1501 数据集上进行训练、测试、推理的过程。 + +##### 2.1.2 数据准备 + +下载 [Market-1501-v15.09.15.zip](https://pan.baidu.com/s/1ntIi2Op?_at_=1654142245770) 数据集,解压到`PaddleClas/dataset/`下,并组织成以下文件结构: + + ```shell + PaddleClas/dataset/market1501 + └── Market-1501-v15.09.15/ + ├── bounding_box_test/ + ├── bounding_box_train/ + ├── gt_bbox/ + ├── gt_query/ + ├── query/ + ├── generate_anno.py + ├── bounding_box_test.txt + ├── bounding_box_train.txt + ├── query.txt + └── readme.txt + ``` + +##### 2.1.3 模型训练 + +1. 执行以下命令开始训练 + + ```shell + python3.7 tools/train.py -c ./ppcls/configs/reid/strong_baseline/softmax_triplet_with_center.yaml + ``` + + 注:单卡训练大约需要1个小时。 + +2. 查看训练日志和保存的模型参数文件 + + 训练过程中会在屏幕上实时打印loss等指标信息,同时会保存日志文件`train.log`、模型参数文件`*.pdparams`、优化器参数文件`*.pdopt`等内容到`Global.output_dir`指定的文件夹下,默认在`PaddleClas/output/RecModel/`文件夹下 + +##### 2.1.4 模型评估 + +准备用于评估的`*.pdparams`模型参数文件,可以使用训练好的模型,也可以使用[2.2 模型训练](#22-模型训练)中保存的模型。 + +- 以训练过程中保存的`latest.pdparams`为例,执行如下命令即可进行评估。 + + ```shell + python3.7 tools/eval.py \ + -c ./ppcls/configs/reid/strong_baseline/softmax_triplet_with_center.yaml \ + -o Global.pretrained_model="./output/RecModel/latest" + ``` + +- 以训练好的模型为例,下载 [reid_strong_baseline_softmax_with_center.epoch_120.pdparams](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/reid_strong_baseline_softmax_with_center.epoch_120.pdparams) 到 `PaddleClas/pretrained_models` 文件夹中,执行如下命令即可进行评估。 + + ```shell + # 下载模型 + cd PaddleClas + mkdir pretrained_models + cd pretrained_models + wget https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/reid_strong_baseline_softmax_with_center.epoch_120.pdparams + cd .. + # 评估 + python3.7 tools/eval.py \ + -c ppcls/configs/reid/strong_baseline/softmax_triplet_with_center.yaml \ + -o Global.pretrained_model="pretrained_models/reid_strong_baseline_softmax_with_center.epoch_120" + ``` + 注:`pretrained_model` 后填入的地址不需要加 `.pdparams` 后缀,在程序运行时会自动补上。 + +- 查看输出结果 + ```log + ... + ... + ppcls INFO: gallery feature calculation process: [0/125] + ppcls INFO: gallery feature calculation process: [20/125] + ppcls INFO: gallery feature calculation process: [40/125] + ppcls INFO: gallery feature calculation process: [60/125] + ppcls INFO: gallery feature calculation process: [80/125] + ppcls INFO: gallery feature calculation process: [100/125] + ppcls INFO: gallery feature calculation process: [120/125] + ppcls INFO: Build gallery done, all feat shape: [15913, 2048], begin to eval.. + ppcls INFO: query feature calculation process: [0/27] + ppcls INFO: query feature calculation process: [20/27] + ppcls INFO: Build query done, all feat shape: [3368, 2048], begin to eval.. + ppcls INFO: re_ranking=False + ppcls INFO: [Eval][Epoch 0][Avg]recall1: 0.94270, recall5: 0.98189, mAP: 0.85799 + ``` + 默认评估日志保存在`PaddleClas/output/RecModel/eval.log`中,可以看到我们提供的 `reid_strong_baseline_softmax_with_center.epoch_120.pdparams` 模型在 Market1501 数据集上的评估指标为recall@1=0.94270,recall@5=0.98189,mAP=0.85799 + +##### 2.1.5 模型推理 + +###### 2.1.5.1 模型导出 +可以选择使用训练过程中保存的模型文件转换成 inference 模型并推理,或者使用我们提供的转换好的 inference 模型直接进行推理 + - 将训练过程中保存的模型文件转换成 inference 模型,同样以`latest.pdparams`为例,执行以下命令进行转换 + ```shell + python3.7 tools/export_model.py \ + -c ppcls/configs/reid/strong_baseline/softmax_triplet_with_center.yaml \ + -o Global.pretrained_model="output/RecModel/latest" \ + -o Global.save_inference_dir="./deploy/reid_srong_baseline_softmax_with_center" + ``` + + - 或者下载并解压我们提供的 inference 模型 + ```shell + cd PaddleClas/deploy + wget https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/reid_srong_baseline_softmax_with_center.tar + tar xf reid_srong_baseline_softmax_with_center.tar + cd ../ + ``` + +###### 2.1.5.2 模型推理 + + 1. 修改 `PaddleClas/deploy/configs/inference_rec.yaml`。将 `infer_imgs:` 后的字段改为 Market1501 中 query 文件夹下的任意一张图片路径(下方代码使用的是`0294_c1s1_066631_00.jpg`图片路径);将 `rec_inference_model_dir:` 后的字段改为解压出来的 reid_srong_baseline_softmax_with_center 文件夹路径;将 `transform_ops` 字段下的预处理配置改为 `softmax_triplet_with_center.yaml` 中`Eval.Query.dataset` 下的预处理配置。如下所示 + + ```yaml + Global: + infer_imgs: "../dataset/market1501/Market-1501-v15.09.15/query/0294_c1s1_066631_00.jpg" + rec_inference_model_dir: "./reid_srong_baseline_softmax_with_center" + batch_size: 1 + use_gpu: False + enable_mkldnn: True + cpu_num_threads: 10 + enable_benchmark: True + use_fp16: False + ir_optim: True + use_tensorrt: False + gpu_mem: 8000 + enable_profile: False + + RecPreProcess: + transform_ops: + - ResizeImage: + size: [128, 256] + return_numpy: False + interpolation: "bilinear" + backend: "pil" + - ToTensor: + - Normalize: + mean: [0.485, 0.456, 0.406] + std: [0.229, 0.224, 0.225] + + RecPostProcess: null + ``` + + 2. 执行推理命令 + + ```shell + cd PaddleClas/deploy/ + python3.7 python/predict_rec.py -c ./configs/inference_rec.yaml + ``` + + 3. 查看输出结果,实际结果为一个长度2048的向量,表示输入图片经过模型转换后得到的特征向量 + + ```shell + 0294_c1s1_066631_00.jpg: [ 0.01806974 0.00476423 -0.00508293 ... 0.03925538 0.00377574 + -0.00849029] + ``` + 推理时的输出向量储存在[predict_rec.py](../../../deploy/python/predict_rec.py#L134-L135)的`result_dict`变量中。 + +### 3. 总结 + +#### 3.1 方法总结与对比 + +上述算法能快速地迁移至多数的ReID模型中,能进一步提升ReID模型的性能。 + #### 3.2 使用建议/FAQ Market1501 数据集比较小,可以尝试训练多次取最高精度。 -#### 4 参考资料 +### 4 参考资料 1. [Bag of Tricks and A Strong Baseline for Deep Person Re-identification](https://openaccess.thecvf.com/content_CVPRW_2019/papers/TRMTMCT/Luo_Bag_of_Tricks_and_a_Strong_Baseline_for_Deep_Person_CVPRW_2019_paper.pdf) -2. [michuanhaohao/reid-strong-baseline: Bag of Tricks and A Strong Baseline for Deep Person Re-identification (github.com)](https://github.com/michuanhaohao/reid-strong-baseline) +2. [michuanhaohao/reid-strong-baseline](https://github.com/michuanhaohao/reid-strong-baseline) 3. [行人重识别数据集之 Market1501 数据集_star_function的博客-CSDN博客_market1501数据集](https://blog.csdn.net/qq_39220334/article/details/121470106) 4. [Deep Learning for Person Re-identification:A Survey and Outlook](https://arxiv.org/abs/2001.04193) diff --git a/ppcls/configs/reid/strong_baseline/baseline.yaml b/ppcls/configs/reid/strong_baseline/baseline.yaml index be9d9b5c8..5c83b8da8 100644 --- a/ppcls/configs/reid/strong_baseline/baseline.yaml +++ b/ppcls/configs/reid/strong_baseline/baseline.yaml @@ -64,42 +64,42 @@ Optimizer: by_epoch: True last_epoch: 0 regularizer: - name: 'L2' + name: "L2" coeff: 0.0005 # data loader for train and eval DataLoader: Train: dataset: - name: "Market1501" - image_root: "./dataset/" - cls_label_path: "bounding_box_train" - backend: "pil" - transform_ops: - - ResizeImage: - size: [128, 256] - return_numpy: False - interpolation: 'bilinear' - backend: "pil" - - RandFlipImage: - flip_code: 1 - - Pad: - padding: 10 - - RandCropImageV2: - size: [128, 256] - - ToTensor: - - Normalize: - mean: [0.485, 0.456, 0.406] - std: [0.229, 0.224, 0.225] + name: "Market1501" + image_root: "./dataset/" + cls_label_path: "bounding_box_train" + backend: "pil" + transform_ops: + - ResizeImage: + size: [128, 256] + return_numpy: False + interpolation: "bilinear" + backend: "pil" + - RandFlipImage: + flip_code: 1 + - Pad: + padding: 10 + - RandCropImageV2: + size: [128, 256] + - ToTensor: + - Normalize: + mean: [0.485, 0.456, 0.406] + std: [0.229, 0.224, 0.225] sampler: - name: DistributedRandomIdentitySampler - batch_size: 64 - num_instances: 4 - drop_last: False - shuffle: True + name: DistributedRandomIdentitySampler + batch_size: 64 + num_instances: 4 + drop_last: False + shuffle: True loader: - num_workers: 4 - use_shared_memory: True + num_workers: 4 + use_shared_memory: True Eval: Query: dataset: @@ -111,7 +111,7 @@ DataLoader: - ResizeImage: size: [128, 256] return_numpy: False - interpolation: 'bilinear' + interpolation: "bilinear" backend: "pil" - ToTensor: - Normalize: @@ -136,7 +136,7 @@ DataLoader: - ResizeImage: size: [128, 256] return_numpy: False - interpolation: 'bilinear' + interpolation: "bilinear" backend: "pil" - ToTensor: - Normalize: diff --git a/ppcls/configs/reid/strong_baseline/softmax_triplet.yaml b/ppcls/configs/reid/strong_baseline/softmax_triplet.yaml index 9694373b0..43f1de62f 100644 --- a/ppcls/configs/reid/strong_baseline/softmax_triplet.yaml +++ b/ppcls/configs/reid/strong_baseline/softmax_triplet.yaml @@ -76,48 +76,48 @@ Optimizer: by_epoch: True last_epoch: 0 regularizer: - name: 'L2' + name: "L2" coeff: 0.0005 # data loader for train and eval DataLoader: Train: dataset: - name: "Market1501" - image_root: "./dataset/" - cls_label_path: "bounding_box_train" - backend: "pil" - transform_ops: - - ResizeImage: - size: [128, 256] - return_numpy: False - interpolation: 'bilinear' - backend: "pil" - - RandFlipImage: - flip_code: 1 - - Pad: - padding: 10 - - RandCropImageV2: - size: [128, 256] - - ToTensor: - - Normalize: - mean: [0.485, 0.456, 0.406] - std: [0.229, 0.224, 0.225] - - RandomErasing: - EPSILON: 0.5 - sl: 0.02 - sh: 0.4 - r1: 0.3 - mean: [0.485, 0.456, 0.406] + name: "Market1501" + image_root: "./dataset/" + cls_label_path: "bounding_box_train" + backend: "pil" + transform_ops: + - ResizeImage: + size: [128, 256] + return_numpy: False + interpolation: "bilinear" + backend: "pil" + - RandFlipImage: + flip_code: 1 + - Pad: + padding: 10 + - RandCropImageV2: + size: [128, 256] + - ToTensor: + - Normalize: + mean: [0.485, 0.456, 0.406] + std: [0.229, 0.224, 0.225] + - RandomErasing: + EPSILON: 0.5 + sl: 0.02 + sh: 0.4 + r1: 0.3 + mean: [0.485, 0.456, 0.406] sampler: - name: DistributedRandomIdentitySampler - batch_size: 64 - num_instances: 4 - drop_last: False - shuffle: True + name: DistributedRandomIdentitySampler + batch_size: 64 + num_instances: 4 + drop_last: False + shuffle: True loader: - num_workers: 4 - use_shared_memory: True + num_workers: 4 + use_shared_memory: True Eval: Query: dataset: @@ -129,7 +129,7 @@ DataLoader: - ResizeImage: size: [128, 256] return_numpy: False - interpolation: 'bilinear' + interpolation: "bilinear" backend: "pil" - ToTensor: - Normalize: @@ -154,7 +154,7 @@ DataLoader: - ResizeImage: size: [128, 256] return_numpy: False - interpolation: 'bilinear' + interpolation: "bilinear" backend: "pil" - ToTensor: - Normalize: diff --git a/ppcls/configs/reid/strong_baseline/softmax_triplet_with_center.yaml b/ppcls/configs/reid/strong_baseline/softmax_triplet_with_center.yaml index b225ebd86..b500fb203 100644 --- a/ppcls/configs/reid/strong_baseline/softmax_triplet_with_center.yaml +++ b/ppcls/configs/reid/strong_baseline/softmax_triplet_with_center.yaml @@ -82,7 +82,7 @@ Optimizer: by_epoch: True last_epoch: 0 regularizer: - name: 'L2' + name: "L2" coeff: 0.0005 - SGD: scope: CenterLoss @@ -94,41 +94,41 @@ Optimizer: DataLoader: Train: dataset: - name: "Market1501" - image_root: "./dataset/" - cls_label_path: "bounding_box_train" - backend: "pil" - transform_ops: - - ResizeImage: - size: [128, 256] - return_numpy: False - interpolation: 'bilinear' - backend: "pil" - - RandFlipImage: - flip_code: 1 - - Pad: - padding: 10 - - RandCropImageV2: - size: [128, 256] - - ToTensor: - - Normalize: - mean: [0.485, 0.456, 0.406] - std: [0.229, 0.224, 0.225] - - RandomErasing: - EPSILON: 0.5 - sl: 0.02 - sh: 0.4 - r1: 0.3 - mean: [0.485, 0.456, 0.406] + name: "Market1501" + image_root: "./dataset/" + cls_label_path: "bounding_box_train" + backend: "pil" + transform_ops: + - ResizeImage: + size: [128, 256] + return_numpy: False + interpolation: "bilinear" + backend: "pil" + - RandFlipImage: + flip_code: 1 + - Pad: + padding: 10 + - RandCropImageV2: + size: [128, 256] + - ToTensor: + - Normalize: + mean: [0.485, 0.456, 0.406] + std: [0.229, 0.224, 0.225] + - RandomErasing: + EPSILON: 0.5 + sl: 0.02 + sh: 0.4 + r1: 0.3 + mean: [0.485, 0.456, 0.406] sampler: - name: DistributedRandomIdentitySampler - batch_size: 64 - num_instances: 4 - drop_last: False - shuffle: True + name: DistributedRandomIdentitySampler + batch_size: 64 + num_instances: 4 + drop_last: False + shuffle: True loader: - num_workers: 4 - use_shared_memory: True + num_workers: 4 + use_shared_memory: True Eval: Query: dataset: @@ -140,7 +140,7 @@ DataLoader: - ResizeImage: size: [128, 256] return_numpy: False - interpolation: 'bilinear' + interpolation: "bilinear" backend: "pil" - ToTensor: - Normalize: @@ -165,7 +165,7 @@ DataLoader: - ResizeImage: size: [128, 256] return_numpy: False - interpolation: 'bilinear' + interpolation: "bilinear" backend: "pil" - ToTensor: - Normalize: From 2e3516deb4ba1c13244b5e8ba5f7652fabf09b94 Mon Sep 17 00:00:00 2001 From: HydrogenSulfate <490868991@qq.com> Date: Wed, 8 Jun 2022 22:07:50 +0800 Subject: [PATCH 4/9] polish reid doc --- docs/zh_CN/algorithm_introduction/reid.md | 94 +++++++++++++++-------- 1 file changed, 63 insertions(+), 31 deletions(-) diff --git a/docs/zh_CN/algorithm_introduction/reid.md b/docs/zh_CN/algorithm_introduction/reid.md index cc2df67f9..e3da7e267 100644 --- a/docs/zh_CN/algorithm_introduction/reid.md +++ b/docs/zh_CN/algorithm_introduction/reid.md @@ -3,20 +3,25 @@ ## 目录 - - [1. 算法/应用场景简介](#1-算法应用场景简介) - - [2. ReID算法](#2-reid算法) - - [2.1 ReID strong-baseline](#21-reid-strong-baseline) - - [2.1.1 原理介绍](#211-原理介绍) - - [2.1.1 数据准备](#211-数据准备) - - [2.1.2 模型训练](#212-模型训练) - - [2.1.3 模型评估](#213-模型评估) - - [2.1.3 模型推理](#213-模型推理) - - [2.1.3.1 模型导出](#2131-模型导出) - - [2.1.3.2 模型推理](#2132-模型推理) - - [3. 总结](#3-总结) - - [3.1 方法总结与对比](#31-方法总结与对比) - - [3.2 使用建议/FAQ](#32-使用建议faq) - - [4 参考资料](#4-参考资料) +- [1. 算法/应用场景简介](#1-算法应用场景简介) +- [2. ReID算法](#2-reid算法) + - [2.1 ReID strong-baseline](#21-reid-strong-baseline) + - [2.1.1 原理介绍](#211-原理介绍) + - [2.1.2 精度指标](#212-精度指标) + - [2.1.3 数据准备](#213-数据准备) + - [2.1.4 模型训练](#214-模型训练) + - [2.1.5 模型评估](#215-模型评估) + - [2.1.6 模型推理部署](#216-模型推理部署) + - [2.1.6.1 推理模型准备](#2161-推理模型准备) + - [2.1.6.2 基于 Python 预测引擎推理](#2162-基于-python-预测引擎推理) + - [2.1.6.3 基于 C++ 预测引擎推理](#2163-基于-c-预测引擎推理) + - [2.1.7 服务化部署](#217-服务化部署) + - [2.1.8 端侧部署](#218-端侧部署) + - [2.1.9 Paddle2ONNX 模型转换与预测](#219-paddle2onnx-模型转换与预测) +- [3. 总结](#3-总结) + - [3.1 方法总结与对比](#31-方法总结与对比) + - [3.2 使用建议/FAQ](#32-使用建议faq) +- [4. 参考资料](#4-参考资料) ### 1. 算法/应用场景简介 @@ -45,6 +50,8 @@ 6. Center loss:给每个类别一个可学习的聚类中心,训练时让类内特征靠近聚类中心,减少类内差异,增大类间差异。 7. Reranking:在检索时考虑查询图像的近邻候选对象,根据候选对象的近邻图像的是否也含有查询图像的情况来优化距离矩阵,最终提升检索精度。 +##### 2.1.2 精度指标 + 以下表格总结了复现的ReID strong-baseline的3种配置在 Market1501 数据集上的精度指标, | 配置文件 | recall@1 | mAP | 参考recall@1 | 参考mAP | @@ -57,7 +64,7 @@ 接下来主要以`softmax_triplet_with_center.yaml`配置和训练好的模型文件为例,展示在 Market1501 数据集上进行训练、测试、推理的过程。 -##### 2.1.2 数据准备 +##### 2.1.3 数据准备 下载 [Market-1501-v15.09.15.zip](https://pan.baidu.com/s/1ntIi2Op?_at_=1654142245770) 数据集,解压到`PaddleClas/dataset/`下,并组织成以下文件结构: @@ -76,7 +83,7 @@ └── readme.txt ``` -##### 2.1.3 模型训练 +##### 2.1.4 模型训练 1. 执行以下命令开始训练 @@ -88,9 +95,9 @@ 2. 查看训练日志和保存的模型参数文件 - 训练过程中会在屏幕上实时打印loss等指标信息,同时会保存日志文件`train.log`、模型参数文件`*.pdparams`、优化器参数文件`*.pdopt`等内容到`Global.output_dir`指定的文件夹下,默认在`PaddleClas/output/RecModel/`文件夹下 + 训练过程中会在屏幕上实时打印loss等指标信息,同时会保存日志文件`train.log`、模型参数文件`*.pdparams`、优化器参数文件`*.pdopt`等内容到`Global.output_dir`指定的文件夹下,默认在`PaddleClas/output/RecModel/`文件夹下 -##### 2.1.4 模型评估 +##### 2.1.5 模型评估 准备用于评估的`*.pdparams`模型参数文件,可以使用训练好的模型,也可以使用[2.2 模型训练](#22-模型训练)中保存的模型。 @@ -138,9 +145,9 @@ ``` 默认评估日志保存在`PaddleClas/output/RecModel/eval.log`中,可以看到我们提供的 `reid_strong_baseline_softmax_with_center.epoch_120.pdparams` 模型在 Market1501 数据集上的评估指标为recall@1=0.94270,recall@5=0.98189,mAP=0.85799 -##### 2.1.5 模型推理 +##### 2.1.6 模型推理部署 -###### 2.1.5.1 模型导出 +###### 2.1.6.1 推理模型准备 可以选择使用训练过程中保存的模型文件转换成 inference 模型并推理,或者使用我们提供的转换好的 inference 模型直接进行推理 - 将训练过程中保存的模型文件转换成 inference 模型,同样以`latest.pdparams`为例,执行以下命令进行转换 ```shell @@ -158,7 +165,7 @@ cd ../ ``` -###### 2.1.5.2 模型推理 +###### 2.1.6.2 基于 Python 预测引擎推理 1. 修改 `PaddleClas/deploy/configs/inference_rec.yaml`。将 `infer_imgs:` 后的字段改为 Market1501 中 query 文件夹下的任意一张图片路径(下方代码使用的是`0294_c1s1_066631_00.jpg`图片路径);将 `rec_inference_model_dir:` 后的字段改为解压出来的 reid_srong_baseline_softmax_with_center 文件夹路径;将 `transform_ops` 字段下的预处理配置改为 `softmax_triplet_with_center.yaml` 中`Eval.Query.dataset` 下的预处理配置。如下所示 @@ -194,18 +201,43 @@ 2. 执行推理命令 - ```shell - cd PaddleClas/deploy/ - python3.7 python/predict_rec.py -c ./configs/inference_rec.yaml - ``` + ```shell + cd PaddleClas/deploy/ + python3.7 python/predict_rec.py -c ./configs/inference_rec.yaml + ``` 3. 查看输出结果,实际结果为一个长度2048的向量,表示输入图片经过模型转换后得到的特征向量 - ```shell - 0294_c1s1_066631_00.jpg: [ 0.01806974 0.00476423 -0.00508293 ... 0.03925538 0.00377574 - -0.00849029] - ``` - 推理时的输出向量储存在[predict_rec.py](../../../deploy/python/predict_rec.py#L134-L135)的`result_dict`变量中。 + ```shell + 0294_c1s1_066631_00.jpg: [ 0.01806974 0.00476423 -0.00508293 ... 0.03925538 0.00377574 + -0.00849029] + ``` + 推理时的输出向量储存在[predict_rec.py](../../../deploy/python/predict_rec.py#L134-L135)的`result_dict`变量中。 + + 4. 批量预测 + 将配置文件中`infer_imgs:`后的路径改为为文件夹即可,如`../dataset/market1501/Market-1501-v15.09.15/query`,则会预测并输出出query下所有图片的特征向量。 + +###### 2.1.6.3 基于 C++ 预测引擎推理 + +PaddleClas 提供了基于 C++ 预测引擎推理的示例,您可以参考[服务器端 C++ 预测](../inference_deployment/cpp_deploy.md)来完成相应的推理部署。如果您使用的是 Windows 平台,可以参考基于 Visual Studio 2019 Community CMake 编译指南完成相应的预测库编译和模型预测工作。 + +##### 2.1.7 服务化部署 + +Paddle Serving 提供高性能、灵活易用的工业级在线推理服务。Paddle Serving 支持 RESTful、gRPC、bRPC 等多种协议,提供多种异构硬件和多种操作系统环境下推理解决方案。更多关于Paddle Serving 的介绍,可以参考Paddle Serving 代码仓库。 + +PaddleClas 提供了基于 Paddle Serving 来完成模型服务化部署的示例,您可以参考[模型服务化部署](../inference_deployment/paddle_serving_deploy.md)来完成相应的部署工作。 + +##### 2.1.8 端侧部署 + +Paddle Lite 是一个高性能、轻量级、灵活性强且易于扩展的深度学习推理框架,定位于支持包括移动端、嵌入式以及服务器端在内的多硬件平台。更多关于 Paddle Lite 的介绍,可以参考Paddle Lite 代码仓库。 + +PaddleClas 提供了基于 Paddle Lite 来完成模型端侧部署的示例,您可以参考[端侧部署](../inference_deployment/paddle_lite_deploy.md)来完成相应的部署工作。 + +##### 2.1.9 Paddle2ONNX 模型转换与预测 + +Paddle2ONNX 支持将 PaddlePaddle 模型格式转化到 ONNX 模型格式。通过 ONNX 可以完成将 Paddle 模型到多种推理引擎的部署,包括TensorRT/OpenVINO/MNN/TNN/NCNN,以及其它对 ONNX 开源格式进行支持的推理引擎或硬件。更多关于 Paddle2ONNX 的介绍,可以参考Paddle2ONNX 代码仓库。 + +PaddleClas 提供了基于 Paddle2ONNX 来完成 inference 模型转换 ONNX 模型并作推理预测的示例,您可以参考[Paddle2ONNX 模型转换与预测](../../../deploy/paddle2onnx/readme.md)来完成相应的部署工作。 ### 3. 总结 @@ -217,7 +249,7 @@ Market1501 数据集比较小,可以尝试训练多次取最高精度。 -### 4 参考资料 +### 4. 参考资料 1. [Bag of Tricks and A Strong Baseline for Deep Person Re-identification](https://openaccess.thecvf.com/content_CVPRW_2019/papers/TRMTMCT/Luo_Bag_of_Tricks_and_a_Strong_Baseline_for_Deep_Person_CVPRW_2019_paper.pdf) 2. [michuanhaohao/reid-strong-baseline](https://github.com/michuanhaohao/reid-strong-baseline) From a31ecc5eb80dc6f616b23147e7cf7bb9889e342a Mon Sep 17 00:00:00 2001 From: HydrogenSulfate <490868991@qq.com> Date: Fri, 10 Jun 2022 16:16:48 +0800 Subject: [PATCH 5/9] polish doc and update en doc --- docs/en/algorithm_introduction/reid.md | 344 +++++++++++++--------- docs/zh_CN/algorithm_introduction/reid.md | 16 +- 2 files changed, 206 insertions(+), 154 deletions(-) diff --git a/docs/en/algorithm_introduction/reid.md b/docs/en/algorithm_introduction/reid.md index 82b8ad4e6..0a74d71a4 100644 --- a/docs/en/algorithm_introduction/reid.md +++ b/docs/en/algorithm_introduction/reid.md @@ -1,122 +1,108 @@ -English|[Simplified Chinese](../../zh_CN/algorithm_introduction/reid.md) +English | [简体中文](../../zh_CN/algorithm_introduction/reid.md) + # ReID pedestrian re-identification +## Table of contents + +- [1. Introduction to algorithms/application scenarios](#1-introduction-to-algorithmsapplication-scenarios) +- [2. ReID algorithm](#2-reid-algorithm) +- [2.1 ReID strong-baseline](#21-reid-strong-baseline) + - [2.1.1 Principle introduction](#211-principle-introduction) + - [2.1.2 Accuracy Index](#212-accuracy-index) + - [2.1.3 Data Preparation](#213-data-preparation) + - [2.1.4 Model training](#214-model-training) + - [2.1.5 Model Evaluation](#215-model-evaluation) + - [2.1.6 Model Inference Deployment](#216-model-inference-deployment) + - [2.1.6.1 Inference model preparation](#2161-inference-model-preparation) + - [2.1.6.2 Inference based on Python prediction engine](#2162-inference-based-on-python-prediction-engine) + - [2.1.6.3 Inference based on C++ prediction engine](#2163-inference-based-on-c-prediction-engine) + - [2.1.7 Service deployment](#217-service-deployment) + - [2.1.8 Device side deployment](#218-device-side-deployment) + - [2.1.9 Paddle2ONNX Model Conversion and Prediction](#219-paddle2onnx-model-conversion-and-prediction) +- [3. Summary](#3-summary) +- [3.1 Method summary and comparison](#31-method-summary-and-comparison) +- [3.2 Usage advice/FAQ](#32-usage-advicefaq) +- [4. References](#4-references) + ### 1. Introduction to algorithms/application scenarios -Pedestrian re-identification (Person re-identification), also known as pedestrian re-identification, is the use of [computer vision](https://baike.baidu.com/item/computer vision/2803351) technology to judge [image](https://baike .baidu.com/item/image/773234) or whether there is a [technique] of a particular pedestrian in the video sequence (https://baike.baidu.com/item/technique/13014499). Widely regarded as a sub-problem of [Image Retrieval](https://baike.baidu.com/item/image_retrieval/1150910). Given a surveillance pedestrian image, retrieve the pedestrian image across devices. It aims to make up for the visual limitations of fixed cameras, and can be combined with [pedestrian detection](https://baike.baidu.com/item/pedestrian detection/20590256)/pedestrian tracking technology, which can be widely used in [intelligent video surveillance] ](https://baike.baidu.com/item/intelligent video surveillance/10717227), intelligent security and other fields. +Pedestrian re-identification (Person re-identification), also known as pedestrian re-identification, is the use of [computer vision](https://baike.baidu.com/item/computervision/2803351) technology to judge [image](https://baike.baidu.com/item/image/773234) or whether there is a technique of a particular pedestrian in the video sequence. Widely regarded as a sub-problem of [Image Retrieval](https://baike.baidu.com/item/image_retrieval/1150910). Given a surveillance pedestrian image, retrieve the pedestrian image across devices. It aims to make up for the visual limitations of fixed cameras, and can be combined with [pedestrian detection](https://baike.baidu.com/item/pedestriandetection/20590256)/pedestrian tracking technology, which can be widely used in [intelligent video surveillance](https://baike.baidu.com/item/intelligentvideosurveillance/10717227), intelligent security and other fields. -### 2. Introduction to ReID strong-baseline algorithm +The common person re-identification method extracts the local/global, single-granularity/multi-granularity features of the input image through the feature extraction module, and then obtains a high-dimensional feature vector through the fusion module. Use the classification head to convert the feature vector into the probability of each category during training to optimize the feature extraction model in the way of classification tasks; directly use the high-dimensional feature vector as the image description vector in the retrieval vector library during testing or inference search to get the search results. The ReID strong-baseline algorithm proposes several methods to effectively optimize training and retrieval to improve the overall model performance. + -In the past person re-identification methods, the feature extraction module is used to extract the global or multi-granularity features of the image, and then a high-dimensional feature vector is obtained through the fusion module. Use the classification head to map the feature vector into the probability of each category during training to optimize the entire model in the way of classification tasks; directly use the high-dimensional feature vector as an image descriptor in the retrieval library during testing or inference. search to get the search results. The ReID strong-baseline algorithm proposes several methods to effectively optimize training and retrieval to improve the overall model performance. +### 2. ReID algorithm -#### 2.1 Principle of ReID strong-baseline algorithm +#### 2.1 ReID strong-baseline Paper source: [Bag of Tricks and A Strong Baseline for Deep Person Re-identification](https://openaccess.thecvf.com/content_CVPRW_2019/papers/TRMTMCT/Luo_Bag_of_Tricks_and_a_Strong_Baseline_for_Deep_Person_CVPRW_2019_paper.pdf) - + -Principle introduction: The author mainly uses the following optimization methods +##### 2.1.1 Principle introduction -1. Warmup, let the learning rate gradually increase at the beginning of training and then start to decrease, which is conducive to finding better parameters during gradient descent. -2. Random erasing augmentation, random area erasing, enhances the generalization of the model. -3. Label smoothing, label smoothing, enhance the generalization of the model. -4. Last stride=1, cancel the downsampling of the last stage of the feature extraction module, increase the resolution of the output feature map to retain more details and enhance the classification ability of the model. -5. BNNeck, before the feature vector is input into the classification head, it goes through BNNeck, so that the feature vector becomes a normal distribution, which reduces the difficulty of optimizing ID Loss and TripLetLoss at the same time. -6. Center loss, give each category a learnable cluster center feature, and make the intra-class features close to the cluster center during training to reduce intra-class differences and increase inter-class differences. -7. Reranking, consider whether the neighboring candidate objects of the retrieved image also contain retrieval targets during retrieval, so as to optimize the distance matrix and finally improve the retrieval accuracy. +Based on the commonly used person re-identification model based on ResNet50, the author explores and summarizes the following effective and applicable optimization methods, which greatly improves the indicators on multiple person re-identification datasets. -#### 2.2a Quick start +1. Warmup: At the beginning of training, let the learning rate gradually increase from a small value and then start to decrease, which is conducive to the stability of gradient descent optimization, so as to find a better parameter model. +2. Random erasing augmentation: Random area erasing, which improves the generalization ability of the model through data augmentation. +3. Label smoothing: Label smoothing to improve the generalization ability of the model. +4. Last stride=1: Set the downsampling of the last stage of the feature extraction module to 1, increase the resolution of the output feature map to retain more details and improve the classification ability of the model. +5. BNNeck: Before the feature vector is input to the classification head, it goes through BNNeck, so that the feature obeys the normal distribution on the surface of the hypersphere, which reduces the difficulty of optimizing IDLoss and TripLetLoss at the same time. +6. Center loss: Give each category a learnable cluster center, and make the intra-class features close to the cluster center during training to reduce intra-class differences and increase inter-class differences. +7. Reranking: Consider the neighbor candidates of the query image during retrieval, optimize the distance matrix according to whether the neighbor images of the candidate object also contain the query image, and finally improve the retrieval accuracy. -The quick start chapter mainly takes the `softmax_triplet_with_center.yaml` configuration and trained model file as an example to test on the Market1501 dataset. +##### 2.1.2 Accuracy Index -1. Download the [Market-1501-v15.09.15.zip](https://pan.baidu.com/s/1ntIi2Op?_at_=1654142245770) dataset, extract it to `PaddleClas/dataset/`, and organize it as follows File structure: +The following table summarizes the accuracy metrics of the 3 configurations of the recurring ReID strong-baseline on the Market1501 dataset, - ```shell - PaddleClas/dataset/market1501 - └── Market-1501-v15.09.15/ - ├── bounding_box_test/ - ├── bounding_box_train/ - ├── gt_bbox/ - ├── gt_query/ - ├── query/ - ├── generate_anno.py - ├── bounding_box_test.txt - ├── bounding_box_train.txt - ├── query.txt - └── readme.txt - ``` +| Profile | recall@1 | mAP | Reference recall@1 | Reference mAP | +| ------------------------ | -------- | ----- | ------------------ | ------------- | +| baseline.yaml | 88.21 | 74.12 | 87.7 | 74.0 | +| softmax.yaml | 94.18 | 85.76 | 94.1 | 85.7 | +| softmax_with_center.yaml | 94.19 | 85.80 | 94.1 | 85.7 | -2. Download [reid_strong_baseline_softmax_with_center.epoch_120.pdparams](reid_strong_baseline_softmax_with_center.epoch_120.pdparams) to `PaddleClas/pretrained_models` folder +Note: The above reference indicators are obtained by using the author's open source code to train on our equipment for many times. Due to different system environment, torch version, CUDA version and other reasons, there may be slight differences with the indicators provided by the author. - ```shell - cd PaddleClas - mkdir pretrained_models - cd pretrained_models - wget https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/reid_strong_baseline_softmax_with_center.epoch_120.pdparams - cd.. - ``` +Next, we mainly take the `softmax_triplet_with_center.yaml` configuration and trained model file as an example to show the process of training, testing, and inference on the Market1501 dataset. -3. Use the downloaded `softmax_triplet_with_center.pdparams` to test on the Market1501 dataset +##### 2.1.3 Data Preparation - ```shell - python3.7 tools/eval.py \ - -c ppcls/configs/reid/strong_baseline/baseline.yaml \ - -o Global.pretrained_model="pretrained_models/reid_strong_baseline_softmax_with_center.epoch_120" - ``` +Download the [Market-1501-v15.09.15.zip](https://pan.baidu.com/s/1ntIi2Op?_at_=1654142245770) dataset, extract it to `PaddleClas/dataset/`, and organize it into the following file structure : -4. View the output result + ```shell + PaddleClas/dataset/market1501 + └── Market-1501-v15.09.15/ + ├── bounding_box_test/ + ├── bounding_box_train/ + ├── gt_bbox/ + ├── gt_query/ + ├── query/ + ├── generate_anno.py + ├── bounding_box_test.txt + ├── bounding_box_train.txt + ├── query.txt + └── readme.txt + ``` - ```log - ... - [2022/06/02 03:08:07] ppcls INFO: gallery feature calculation process: [0/125] - [2022/06/02 03:08:11] ppcls INFO: gallery feature calculation process: [20/125] - [2022/06/02 03:08:15] ppcls INFO: gallery feature calculation process: [40/125] - [2022/06/02 03:08:19] ppcls INFO: gallery feature calculation process: [60/125] - [2022/06/02 03:08:23] ppcls INFO: gallery feature calculation process: [80/125] - [2022/06/02 03:08:27] ppcls INFO: gallery feature calculation process: [100/125] - [2022/06/02 03:08:31] ppcls INFO: gallery feature calculation process: [120/125] - [2022/06/02 03:08:32] ppcls INFO: Build gallery done, all feat shape: [15913, 2048], begin to eval.. - [2022/06/02 03:08:33] ppcls INFO: query feature calculation process: [0/27] - [2022/06/02 03:08:36] ppcls INFO: query feature calculation process: [20/27] - [2022/06/02 03:08:38] ppcls INFO: Build query done, all feat shape: [3368, 2048], begin to eval.. - [2022/06/02 03:08:38] ppcls INFO: re_ranking=False - [2022/06/02 03:08:39] ppcls INFO: [Eval][Epoch 0][Avg]recall1: 0.94270, recall5: 0.98189, mAP: 0.85799 - ``` +##### 2.1.4 Model training - It can be seen that the metrics of the `reid_strong_baseline_softmax_with_center.epoch_120.pdparams` model provided by us on the Market1501 dataset are recall@1=0.94270, recall@5=0.98189, mAP=0.85799 +1. Execute the following command to start training -#### 2.2b Model training/testing/inference + ```shell + python3.7 tools/train.py -c ./ppcls/configs/reid/strong_baseline/softmax_triplet_with_center.yaml + ``` -- Model training + Note: Single card training takes about 1 hour. - 1. Download the [Market-1501-v15.09.15.zip](https://pan.baidu.com/s/1ntIi2Op?_at_=1654142245770) dataset, extract it to `PaddleClas/dataset/`, and organize it as follows File structure: +2. View training logs and saved model parameter files - ```shell - PaddleClas/dataset/market1501 - └── Market-1501-v15.09.15/ - ├── bounding_box_test/ - ├── bounding_box_train/ - ├── gt_bbox/ - ├── gt_query/ - ├── query/ - ├── generate_anno.py - ├── bounding_box_test.txt - ├── bounding_box_train.txt - ├── query.txt - └── readme.txt - ``` + During the training process, indicator information such as loss will be printed on the screen in real time, and the log file `train.log`, model parameter file `*.pdparams`, optimizer parameter file `*.pdopt` and other contents will be saved to `Global.output_dir` `Under the specified folder, the default is under the `PaddleClas/output/RecModel/` folder. - 2. Execute the following command to start training +##### 2.1.5 Model Evaluation - ```shell - python3.7 tools/train.py -c ./ppcls/configs/reid/strong_baseline/softmax_triplet_with_center.yaml - ``` +Prepare the `*.pdparams` model parameter file for evaluation. You can use the trained model or the model saved in [2.1.4 Model training](#214-model-training). - Note: Single card training takes about 1 hour. - -- Model testing - - Assuming that the path of the model file to be tested is `./output/RecModel/latest.pdparams` , execute the following command to test +- Take the `latest.pdparams` saved during training as an example, execute the following command to evaluate. ```shell python3.7 tools/eval.py \ @@ -124,83 +110,149 @@ The quick start chapter mainly takes the `softmax_triplet_with_center.yaml` conf -o Global.pretrained_model="./output/RecModel/latest" ``` +- Take the trained model as an example, download [reid_strong_baseline_softmax_with_center.epoch_120.pdparams](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/reid_strong_baseline_softmax_with_center.epoch_120.pdparams) Go to the `PaddleClas/pretrained_models` folder and execute the following command to evaluate. + + ```shell + # download model + cd PaddleClas + mkdir pretrained_models + cd pretrained_models + wget https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/reid_strong_baseline_softmax_with_center.epoch_120.pdparams + cd.. + # Evaluate + python3.7 tools/eval.py \ + -c ppcls/configs/reid/strong_baseline/softmax_triplet_with_center.yaml \ + -o Global.pretrained_model="pretrained_models/reid_strong_baseline_softmax_with_center.epoch_120" + ``` Note: The address filled after `pretrained_model` does not need to be suffixed with `.pdparams`, it will be added automatically when the program is running. -- Model inference +- View output results + ```log + ... + ... + ppcls INFO: gallery feature calculation process: [0/125] + ppcls INFO: gallery feature calculation process: [20/125] + ppcls INFO: gallery feature calculation process: [40/125] + ppcls INFO: gallery feature calculation process: [60/125] + ppcls INFO: gallery feature calculation process: [80/125] + ppcls INFO: gallery feature calculation process: [100/125] + ppcls INFO: gallery feature calculation process: [120/125] + ppcls INFO: Build gallery done, all feat shape: [15913, 2048], begin to eval.. + ppcls INFO: query feature calculation process: [0/27] + ppcls INFO: query feature calculation process: [20/27] + ppcls INFO: Build query done, all feat shape: [3368, 2048], begin to eval.. + ppcls INFO: re_ranking=False + ppcls INFO: [Eval][Epoch 0][Avg]recall1: 0.94270, recall5: 0.98189, mAP: 0.85799 + ``` + The default evaluation log is saved in `PaddleClas/output/RecModel/eval.log`. You can see that the evaluation metrics of the `reid_strong_baseline_softmax_with_center.epoch_120.pdparams` model we provided on the Market1501 dataset are recall@1=0.94270, recall@5 =0.98189, mAP=0.85799 - 1. DownloadInference model and extract: [reid_srong_baseline_softmax_with_center.tar](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/reid_srong_baseline_softmax_with_center.tar) +##### 2.1.6 Model Inference Deployment - ```shell - cd PaddleClas/deploy - wget https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/reid_srong_baseline_softmax_with_center.tar - tar xf reid_srong_baseline_softmax_with_center.tar - ``` +###### 2.1.6.1 Inference model preparation +You can choose to use the model file saved during the training process to convert into an inference model and inference, or use the converted inference model we provide for direct inference + - Convert the model file saved during the training process into an inference model, also take `latest.pdparams` as an example, execute the following command to convert + ```shell + python3.7 tools/export_model.py \ + -c ppcls/configs/reid/strong_baseline/softmax_triplet_with_center.yaml \ + -o Global.pretrained_model="output/RecModel/latest" \ + -o Global.save_inference_dir="./deploy/reid_srong_baseline_softmax_with_center" + ``` - 2. Modify `PaddleClas/deploy/configs/inference_rec.yaml`. Change the field after `infer_imgs:` to any image in the query folder in Market1501; change the field after `rec_inference_model_dir:` to the path of the extracted reid_srong_baseline_softmax_with_center folder; change the preprocessing configuration under the `transform_ops` field Changed to preprocessing configuration under `Eval.Query.dataset` in `softmax_triplet_with_center.yaml`. As follows + - Or download and unzip the inference model we provide + ```shell + cd PaddleClas/deploy + wget https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/reid_srong_baseline_softmax_with_center.tar + tar xf reid_srong_baseline_softmax_with_center.tar + cd ../ + ``` - ```yaml - Global: - infer_imgs: "../dataset/market1501/Market-1501-v15.09.15/query/0294_c1s1_066631_00.jpg" - rec_inference_model_dir: "./reid_srong_baseline_softmax_with_center" - batch_size: 1 - use_gpu: False - enable_mkldnn: True - cpu_num_threads: 10 - enable_benchmark: True - use_fp16: False - ir_optim: True - use_tensorrt: False - gpu_mem: 8000 - enable_profile: False +###### 2.1.6.2 Inference based on Python prediction engine - RecPreProcess: - transform_ops: - -ResizeImage: - size: [128, 256] - return_numpy: False - interpolation: 'bilinear' - backend: "pil" - - ToTensor: - - Normalize: - mean: [0.485, 0.456, 0.406] - std: [0.229, 0.224, 0.225] + 1. Modify `PaddleClas/deploy/configs/inference_rec.yaml`. Change the field after `infer_imgs:` to any image path under the query folder in Market1501 (the code below uses the image path of `0294_c1s1_066631_00.jpg`); change the field after `rec_inference_model_dir:` to the extracted one reid_srong_baseline_softmax_with_center folder path; change the preprocessing configuration under the `transform_ops` field to the preprocessing configuration under `Eval.Query.dataset` in `softmax_triplet_with_center.yaml`. As follows - RecPostProcess: null - ``` + ```yaml + Global: + infer_imgs: "../dataset/market1501/Market-1501-v15.09.15/query/0294_c1s1_066631_00.jpg" + rec_inference_model_dir: "./reid_srong_baseline_softmax_with_center" + batch_size: 1 + use_gpu: False + enable_mkldnn: True + cpu_num_threads: 10 + enable_benchmark: True + use_fp16: False + ir_optim: True + use_tensorrt: False + gpu_mem: 8000 + enable_profile: False - 3. Execute the inference command + RecPreProcess: + transform_ops: + -ResizeImage: + size: [128, 256] + return_numpy: False + interpolation: "bilinear" + backend: "pil" + - ToTensor: + - Normalize: + mean: [0.485, 0.456, 0.406] + std: [0.229, 0.224, 0.225] - ```shell - python3.7 python/predict_rec.py -c ./configs/inference_rec.yaml - ``` + RecPostProcess: null + ``` - 4. Check the output result. The actual result is a vector of length 2048, which represents the feature vector obtained after the input image is transformed by the model. + 2. Execute the inference command - ```shell - 0294_c1s1_066631_00.jpg: [ 0.01806974 0.00476423 -0.00508293 ... 0.03925538 0.00377574 - -0.00849029] - ``` + ```shell + cd PaddleClas/deploy/ + python3.7 python/predict_rec.py -c ./configs/inference_rec.yaml + ``` + + 3. Check the output result, the actual result is a vector of length 2048, which represents the feature vector obtained after the input image is transformed by the model + + ```shell + 0294_c1s1_066631_00.jpg: [ 0.01806974 0.00476423 -0.00508293 ... 0.03925538 0.00377574 + -0.00849029] + ``` + The output vector for inference is stored in the `result_dict` variable in [predict_rec.py](../../../deploy/python/predict_rec.py#L134-L135). + + 4. Batch prediction + Change the path after `infer_imgs:` in the configuration file to a folder, such as `../dataset/market1501/Market-1501-v15.09.15/query`, it will predict and output all images under query. Feature vector. + +###### 2.1.6.3 Inference based on C++ prediction engine + +PaddleClas provides an example of inference based on the C++ prediction engine, you can refer to [Server-side C++ prediction](../inference_deployment/cpp_deploy_en.md) to complete the corresponding inference deployment. If you are using the Windows platform, you can refer to the Visual Studio 2019 Community CMake Compilation Guide to complete the corresponding prediction library compilation and model prediction work. + +##### 2.1.7 Service deployment + +Paddle Serving provides high-performance, flexible and easy-to-use industrial-grade online inference services. Paddle Serving supports RESTful, gRPC, bRPC and other protocols, and provides inference solutions in a variety of heterogeneous hardware and operating system environments. For more introduction to Paddle Serving, please refer to the Paddle Serving code repository. + +PaddleClas provides an example of model serving deployment based on Paddle Serving. You can refer to [Model serving deployment](../inference_deployment/paddle_serving_deploy_en.md) to complete the corresponding deployment. + +##### 2.1.8 Device side deployment + +Paddle Lite is a high-performance, lightweight, flexible and easily extensible deep learning inference framework, positioned to support multiple hardware platforms including mobile, embedded and server. For more introduction to Paddle Lite, please refer to the Paddle Lite code repository. + +PaddleClas provides an example of deploying models based on Paddle Lite. You can refer to [Deployment](../inference_deployment/paddle_lite_deploy_en.md) to complete the corresponding deployment. + +##### 2.1.9 Paddle2ONNX Model Conversion and Prediction + +Paddle2ONNX supports converting PaddlePaddle model format to ONNX model format. The deployment of Paddle models to various inference engines can be completed through ONNX, including TensorRT/OpenVINO/MNN/TNN/NCNN, and other inference engines or hardware that support the ONNX open source format. For more information about Paddle2ONNX, please refer to the Paddle2ONNX code repository. + +PaddleClas provides an example of converting an inference model to an ONNX model and making inference prediction based on Paddle2ONNX. You can refer to [Paddle2ONNX model conversion and prediction](../../../deploy/paddle2onnx/readme.md) to complete the corresponding deployment work. ### 3. Summary -#### 3.1 Method summary, comparison, etc. +#### 3.1 Method summary and comparison -The following table summarizes the accuracy metrics of the 3 configurations of ReID strong-baseline we provide on the Market1501 dataset, - -| Profile | recall@1 | mAP | Reference recall@1 | Reference mAP | -| ------------------------ | -------- | ----- | ------------ | ------- | -| baseline.yaml | 88.21 | 74.12 | 87.7 | 74.0 | -| softmax.yaml | 94.18 | 85.76 | 94.1 | 85.7 | -| softmax_with_center.yaml | 94.19 | 85.80 | 94.1 | 85.7 | - -Note: The above reference indicators are obtained by using the author's open source code to train on our equipment for many times. Due to different system environments, torch versions, and CUDA versions, there may be slight differences with the indicators provided by the author. +The above algorithm can be quickly migrated to most ReID models, which can further improve the performance of ReID models. #### 3.2 Usage advice/FAQ The Market1501 dataset is relatively small, so you can try to train multiple times to get the highest accuracy. -#### 4 References +### 4. References 1. [Bag of Tricks and A Strong Baseline for Deep Person Re-identification](https://openaccess.thecvf.com/content_CVPRW_2019/papers/TRMTMCT/Luo_Bag_of_Tricks_and_a_Strong_Baseline_for_Deep_Person_CVPRW_2019_paper.pdf) -2. [michuanhaohao/reid-strong-baseline: Bag of Tricks and A Strong Baseline for Deep Person Re-identification (github.com)](https://github.com/michuanhaohao/reid-strong-baseline) -3. [Pedestrian Re-ID dataset Market1501 dataset _star_function blog-CSDN blog _market1501 dataset](https://blog.csdn.net/qq_39220334/article/details/121470106) +2. [michuanhaohao/reid-strong-baseline](https://github.com/michuanhaohao/reid-strong-baseline) +3. [Pedestrian Re-ID dataset Market1501Data set _star_function's blog - CSDN blog _market1501 data set](https://blog.csdn.net/qq_39220334/article/details/121470106) +4. [Deep Learning for Person Re-identification: A Survey and Outlook](https://arxiv.org/abs/2001.04193) diff --git a/docs/zh_CN/algorithm_introduction/reid.md b/docs/zh_CN/algorithm_introduction/reid.md index e3da7e267..42d069329 100644 --- a/docs/zh_CN/algorithm_introduction/reid.md +++ b/docs/zh_CN/algorithm_introduction/reid.md @@ -1,4 +1,5 @@ -简体中文|[English](../../en/algorithm_introduction/reid.md) +简体中文 | [English](../../en/algorithm_introduction/reid.md) + # ReID行人重识别 ## 目录 @@ -25,7 +26,7 @@ ### 1. 算法/应用场景简介 -行人重识别(Person re-identification)也称行人再识别,是利用[计算机视觉](https://baike.baidu.com/item/计算机视觉/2803351)技术判断[图像](https://baike.baidu.com/item/图像/773234)或者视频序列中是否存在特定行人的[技术](https://baike.baidu.com/item/技术/13014499)。广泛被认为是一个[图像检索](https://baike.baidu.com/item/图像检索/1150910)的子问题。给定一个监控行人图像,检索跨设备下的该行人图像。旨在弥补固定的摄像头的视觉局限,并可与[行人检测](https://baike.baidu.com/item/行人检测/20590256)/行人跟踪技术相结合,可广泛应用于[智能视频监控](https://baike.baidu.com/item/智能视频监控/10717227)、智能安保等领域。 +行人重识别(Person re-identification)也称行人再识别,是利用[计算机视觉](https://baike.baidu.com/item/计算机视觉/2803351)技术判断[图像](https://baike.baidu.com/item/图像/773234)或者视频序列中是否存在特定行人的技术。广泛被认为是一个[图像检索](https://baike.baidu.com/item/图像检索/1150910)的子问题。给定一个监控行人图像,检索跨设备下的该行人图像。旨在弥补固定的摄像头的视觉局限,并可与[行人检测](https://baike.baidu.com/item/行人检测/20590256)/行人跟踪技术相结合,可广泛应用于[智能视频监控](https://baike.baidu.com/item/智能视频监控/10717227)、智能安保等领域。 常见的行人重识别方法通过特征提取模块来提取输入图片的局部/全局、单粒度/多粒度特征,再经过融合模块得到一个高维的特征向量。在训练时使用分类头将该特征向量转换成属于每个类别的概率从而以分类任务的方式来优化特征提取模型;在测试或推理时直接将高维的特征向量作为图片描述向量在检索向量库中进行检索,以得到检索结果。而ReID strong-baseline算法则是提出了多个有效优化训练与检索的方法来提升整体模型性能。 @@ -36,7 +37,7 @@ 论文出处:[Bag of Tricks and A Strong Baseline for Deep Person Re-identification](https://openaccess.thecvf.com/content_CVPRW_2019/papers/TRMTMCT/Luo_Bag_of_Tricks_and_a_Strong_Baseline_for_Deep_Person_CVPRW_2019_paper.pdf) - + ##### 2.1.1 原理介绍 @@ -95,11 +96,11 @@ 2. 查看训练日志和保存的模型参数文件 - 训练过程中会在屏幕上实时打印loss等指标信息,同时会保存日志文件`train.log`、模型参数文件`*.pdparams`、优化器参数文件`*.pdopt`等内容到`Global.output_dir`指定的文件夹下,默认在`PaddleClas/output/RecModel/`文件夹下 + 训练过程中会在屏幕上实时打印loss等指标信息,同时会保存日志文件`train.log`、模型参数文件`*.pdparams`、优化器参数文件`*.pdopt`等内容到`Global.output_dir`指定的文件夹下,默认在`PaddleClas/output/RecModel/`文件夹下。 ##### 2.1.5 模型评估 -准备用于评估的`*.pdparams`模型参数文件,可以使用训练好的模型,也可以使用[2.2 模型训练](#22-模型训练)中保存的模型。 +准备用于评估的`*.pdparams`模型参数文件,可以使用训练好的模型,也可以使用[2.1.4 模型训练](#214-模型训练)中保存的模型。 - 以训练过程中保存的`latest.pdparams`为例,执行如下命令即可进行评估。 @@ -167,7 +168,7 @@ ###### 2.1.6.2 基于 Python 预测引擎推理 - 1. 修改 `PaddleClas/deploy/configs/inference_rec.yaml`。将 `infer_imgs:` 后的字段改为 Market1501 中 query 文件夹下的任意一张图片路径(下方代码使用的是`0294_c1s1_066631_00.jpg`图片路径);将 `rec_inference_model_dir:` 后的字段改为解压出来的 reid_srong_baseline_softmax_with_center 文件夹路径;将 `transform_ops` 字段下的预处理配置改为 `softmax_triplet_with_center.yaml` 中`Eval.Query.dataset` 下的预处理配置。如下所示 + 1. 修改 `PaddleClas/deploy/configs/inference_rec.yaml`。将 `infer_imgs:` 后的字段改为 Market1501 中 query 文件夹下的任意一张图片路径(下方配置使用的是`0294_c1s1_066631_00.jpg`图片的路径);将 `rec_inference_model_dir:` 后的字段改为解压出来的 reid_srong_baseline_softmax_with_center 文件夹路径;将 `transform_ops` 字段下的预处理配置改为 `softmax_triplet_with_center.yaml` 中`Eval.Query.dataset` 下的预处理配置。如下所示 ```yaml Global: @@ -214,8 +215,7 @@ ``` 推理时的输出向量储存在[predict_rec.py](../../../deploy/python/predict_rec.py#L134-L135)的`result_dict`变量中。 - 4. 批量预测 - 将配置文件中`infer_imgs:`后的路径改为为文件夹即可,如`../dataset/market1501/Market-1501-v15.09.15/query`,则会预测并输出出query下所有图片的特征向量。 + 4. 批量预测,将配置文件中`infer_imgs:`后的路径改为为文件夹即可,如`../dataset/market1501/Market-1501-v15.09.15/query`,则会预测并输出出query下所有图片的特征向量。 ###### 2.1.6.3 基于 C++ 预测引擎推理 From 8fb733ff637e7556b9af7cc08333d5c66355d291 Mon Sep 17 00:00:00 2001 From: HydrogenSulfate <490868991@qq.com> Date: Thu, 23 Jun 2022 14:43:54 +0800 Subject: [PATCH 6/9] polish reid docs --- docs/en/algorithm_introduction/reid.md | 146 +++++++++++++--------- docs/zh_CN/algorithm_introduction/reid.md | 126 +++++++++++-------- 2 files changed, 162 insertions(+), 110 deletions(-) diff --git a/docs/en/algorithm_introduction/reid.md b/docs/en/algorithm_introduction/reid.md index 0a74d71a4..2f8d3c28b 100644 --- a/docs/en/algorithm_introduction/reid.md +++ b/docs/en/algorithm_introduction/reid.md @@ -6,27 +6,28 @@ English | [简体中文](../../zh_CN/algorithm_introduction/reid.md) - [1. Introduction to algorithms/application scenarios](#1-introduction-to-algorithmsapplication-scenarios) - [2. ReID algorithm](#2-reid-algorithm) -- [2.1 ReID strong-baseline](#21-reid-strong-baseline) - - [2.1.1 Principle introduction](#211-principle-introduction) - - [2.1.2 Accuracy Index](#212-accuracy-index) - - [2.1.3 Data Preparation](#213-data-preparation) - - [2.1.4 Model training](#214-model-training) - - [2.1.5 Model Evaluation](#215-model-evaluation) - - [2.1.6 Model Inference Deployment](#216-model-inference-deployment) - - [2.1.6.1 Inference model preparation](#2161-inference-model-preparation) - - [2.1.6.2 Inference based on Python prediction engine](#2162-inference-based-on-python-prediction-engine) - - [2.1.6.3 Inference based on C++ prediction engine](#2163-inference-based-on-c-prediction-engine) - - [2.1.7 Service deployment](#217-service-deployment) - - [2.1.8 Device side deployment](#218-device-side-deployment) - - [2.1.9 Paddle2ONNX Model Conversion and Prediction](#219-paddle2onnx-model-conversion-and-prediction) -- [3. Summary](#3-summary) -- [3.1 Method summary and comparison](#31-method-summary-and-comparison) -- [3.2 Usage advice/FAQ](#32-usage-advicefaq) + - [2.1 ReID strong-baseline](#21-reid-strong-baseline) + - [2.1.1 Principle introduction](#211-principle-introduction) + - [2.1.2 Accuracy Index](#212-accuracy-index) + - [2.1.3 Data Preparation](#213-data-preparation) + - [2.1.4 Model training](#214-model-training) +- [3. Model evaluation and inference deployment](#3-model-evaluation-and-inference-deployment) + - [3.1 Model Evaluation](#31-model-evaluation) + - [3.1 Model Inference and Deployment](#31-model-inference-and-deployment) + - [3.1.1 Inference model preparation](#311-inference-model-preparation) + - [3.1.2 Inference based on Python prediction engine](#312-inference-based-on-python-prediction-engine) + - [3.1.3 Inference based on C++ prediction engine](#313-inference-based-on-c-prediction-engine) + - [3.2 Service Deployment](#32-service-deployment) + - [3.3 Device side deployment](#33-device-side-deployment) + - [3.4 Paddle2ONNX model conversion and prediction](#34-paddle2onnx-model-conversion-and-prediction) +- [4. Summary](#4-summary) + - [4.1 Method summary and comparison](#41-method-summary-and-comparison) + - [4.2 Usage advice/FAQ](#42-usage-advicefaq) - [4. References](#4-references) ### 1. Introduction to algorithms/application scenarios -Pedestrian re-identification (Person re-identification), also known as pedestrian re-identification, is the use of [computer vision](https://baike.baidu.com/item/computervision/2803351) technology to judge [image](https://baike.baidu.com/item/image/773234) or whether there is a technique of a particular pedestrian in the video sequence. Widely regarded as a sub-problem of [Image Retrieval](https://baike.baidu.com/item/image_retrieval/1150910). Given a surveillance pedestrian image, retrieve the pedestrian image across devices. It aims to make up for the visual limitations of fixed cameras, and can be combined with [pedestrian detection](https://baike.baidu.com/item/pedestriandetection/20590256)/pedestrian tracking technology, which can be widely used in [intelligent video surveillance](https://baike.baidu.com/item/intelligentvideosurveillance/10717227), intelligent security and other fields. +Pedestrian re-identification, also known as pedestrian re-identification, is a technology that uses computer vision technology to determine whether there is a specific pedestrian in an image or video sequence. Widely regarded as a sub-problem of image retrieval. Given a surveillance pedestrian image, retrieve the pedestrian image across devices. It is designed to make up for the visual limitations of fixed cameras, and can be combined with pedestrian detection/pedestrian tracking technology, which can be widely used in intelligent video surveillance, intelligent security and other fields. The common person re-identification method extracts the local/global, single-granularity/multi-granularity features of the input image through the feature extraction module, and then obtains a high-dimensional feature vector through the fusion module. Use the classification head to convert the feature vector into the probability of each category during training to optimize the feature extraction model in the way of classification tasks; directly use the high-dimensional feature vector as the image description vector in the retrieval vector library during testing or inference search to get the search results. The ReID strong-baseline algorithm proposes several methods to effectively optimize training and retrieval to improve the overall model performance. @@ -55,13 +56,13 @@ Based on the commonly used person re-identification model based on ResNet50, the The following table summarizes the accuracy metrics of the 3 configurations of the recurring ReID strong-baseline on the Market1501 dataset, -| Profile | recall@1 | mAP | Reference recall@1 | Reference mAP | -| ------------------------ | -------- | ----- | ------------------ | ------------- | -| baseline.yaml | 88.21 | 74.12 | 87.7 | 74.0 | -| softmax.yaml | 94.18 | 85.76 | 94.1 | 85.7 | -| softmax_with_center.yaml | 94.19 | 85.80 | 94.1 | 85.7 | +| Configuration file | recall@1 | mAP | Refer to recall@1 | Refer to mAP | Pre-trained model download | Inference Model Download Address | +| -------------------------------- | -------- | ----- | ----------------- | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | +| baseline.yaml | 88.45 | 74.37 | 87.7 | 74.0 | [Download link](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/baseline_pretrained.pdparams) | [Download link](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/baseline_infer.tar) | +| softmax_triplet.yaml | 94.29 | 85.57 | 94.1 | 85.7 | [Download link](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/softmax_triplet_pretrained.pdparams) | [Download link](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/softmax_triplet_infer.tar) | +| softmax_triplet_with_center.yaml | 94.50 | 85.82 | 94.5 | 85.9 | [Download link](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/softmax_triplet_with_center_pretrained.pdparams) | [Download link](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/softmax_triplet_with_center_infer.tar) | -Note: The above reference indicators are obtained by using the author's open source code to train on our equipment for many times. Due to different system environment, torch version, CUDA version and other reasons, there may be slight differences with the indicators provided by the author. +Note: The above reference indicators are obtained by using the author's open source code to train on our equipment for many times. Due to different system environments, torch versions, and CUDA versions, there may be slight differences with the indicators provided by the author. Next, we mainly take the `softmax_triplet_with_center.yaml` configuration and trained model file as an example to show the process of training, testing, and inference on the Market1501 dataset. @@ -72,15 +73,15 @@ Download the [Market-1501-v15.09.15.zip](https://pan.baidu.com/s/1ntIi2Op?_at_=1 ```shell PaddleClas/dataset/market1501 └── Market-1501-v15.09.15/ - ├── bounding_box_test/ - ├── bounding_box_train/ + ├── bounding_box_test/ # gallery set pictures + ├── bounding_box_train/ # training set image ├── gt_bbox/ ├── gt_query/ - ├── query/ + ├── query/ # query set image ├── generate_anno.py - ├── bounding_box_test.txt - ├── bounding_box_train.txt - ├── query.txt + ├── bounding_box_test.txt # gallery set path + ├── bounding_box_train.txt # training set path + ├── query.txt # query set path └── readme.txt ``` @@ -88,19 +89,40 @@ Download the [Market-1501-v15.09.15.zip](https://pan.baidu.com/s/1ntIi2Op?_at_=1 1. Execute the following command to start training + Single card training: ```shell python3.7 tools/train.py -c ./ppcls/configs/reid/strong_baseline/softmax_triplet_with_center.yaml ``` + Doka training: + + For Doka training, you need to modify the sampler field of the training configuration as follows: + ```yaml + sampler: + name: PKSampler + batch_size: 64 + sample_per_id: 4 + drop_last: False + sample_method: id_avg_prob + shuffle: True + ``` + Then execute the following command(example of 4 gpus below): + ```shell + export CUDA_VISIBLE_DEVICES=0,1,2,3 + python3.7 -m paddle.distributed.launch --gpus="0,1,2,3" tools/train.py \ + -c ./ppcls/configs/reid/strong_baseline/softmax_triplet_with_center.yaml + ``` Note: Single card training takes about 1 hour. 2. View training logs and saved model parameter files During the training process, indicator information such as loss will be printed on the screen in real time, and the log file `train.log`, model parameter file `*.pdparams`, optimizer parameter file `*.pdopt` and other contents will be saved to `Global.output_dir` `Under the specified folder, the default is under the `PaddleClas/output/RecModel/` folder. -##### 2.1.5 Model Evaluation +### 3. Model evaluation and inference deployment -Prepare the `*.pdparams` model parameter file for evaluation. You can use the trained model or the model saved in [2.1.4 Model training](#214-model-training). +#### 3.1 Model Evaluation + +Prepare the `*.pdparams` model parameter file for evaluation. You can use the trained model or the model saved in [2.1.4 Model training] (#214-model training). - Take the `latest.pdparams` saved during training as an example, execute the following command to evaluate. @@ -110,19 +132,19 @@ Prepare the `*.pdparams` model parameter file for evaluation. You can use the tr -o Global.pretrained_model="./output/RecModel/latest" ``` -- Take the trained model as an example, download [reid_strong_baseline_softmax_with_center.epoch_120.pdparams](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/reid_strong_baseline_softmax_with_center.epoch_120.pdparams) Go to the `PaddleClas/pretrained_models` folder and execute the following command to evaluate. +- to train wellTake the model as an example, download [softmax_triplet_with_center_pretrained.pdparams](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/softmax_triplet_with_center_pretrained.pdparams) to `PaddleClas/ In the pretrained_models` folder, execute the following command to evaluate. ```shell # download model cd PaddleClas mkdir pretrained_models cd pretrained_models - wget https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/reid_strong_baseline_softmax_with_center.epoch_120.pdparams + wget https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/softmax_triplet_with_center_pretrained.pdparams cd.. # Evaluate python3.7 tools/eval.py \ -c ppcls/configs/reid/strong_baseline/softmax_triplet_with_center.yaml \ - -o Global.pretrained_model="pretrained_models/reid_strong_baseline_softmax_with_center.epoch_120" + -o Global.pretrained_model="pretrained_models/softmax_triplet_with_center_pretrained" ``` Note: The address filled after `pretrained_model` does not need to be suffixed with `.pdparams`, it will be added automatically when the program is running. @@ -130,6 +152,8 @@ Prepare the `*.pdparams` model parameter file for evaluation. You can use the tr ```log ... ... + ppcls INFO: unique_endpoints {''} + ppcls INFO: Found /root/.paddleclas/weights/resnet50-19c8e357_torch2paddle.pdparams ppcls INFO: gallery feature calculation process: [0/125] ppcls INFO: gallery feature calculation process: [20/125] ppcls INFO: gallery feature calculation process: [40/125] @@ -142,38 +166,39 @@ Prepare the `*.pdparams` model parameter file for evaluation. You can use the tr ppcls INFO: query feature calculation process: [20/27] ppcls INFO: Build query done, all feat shape: [3368, 2048], begin to eval.. ppcls INFO: re_ranking=False - ppcls INFO: [Eval][Epoch 0][Avg]recall1: 0.94270, recall5: 0.98189, mAP: 0.85799 + ppcls INFO: [Eval][Epoch 0][Avg]recall1: 0.94507, recall5: 0.98248, mAP: 0.85827 ``` - The default evaluation log is saved in `PaddleClas/output/RecModel/eval.log`. You can see that the evaluation metrics of the `reid_strong_baseline_softmax_with_center.epoch_120.pdparams` model we provided on the Market1501 dataset are recall@1=0.94270, recall@5 =0.98189, mAP=0.85799 + The default evaluation log is saved in `PaddleClas/output/RecModel/eval.log`. You can see that the evaluation metrics of the `softmax_triplet_with_center_pretrained.pdparams` model we provided on the Market1501 dataset are recall@1=0.94507, recall@5 =0.98248, mAP=0.85827 -##### 2.1.6 Model Inference Deployment +#### 3.1 Model Inference and Deployment -###### 2.1.6.1 Inference model preparation -You can choose to use the model file saved during the training process to convert into an inference model and inference, or use the converted inference model we provide for direct inference - - Convert the model file saved during the training process into an inference model, also take `latest.pdparams` as an example, execute the following command to convert +##### 3.1.1 Inference model preparation + +You can convert the model file saved during training into an inference model and inference, or use the converted inference model we provide for direct inference + - Convert the model file saved during the training process to an inference model, also take `latest.pdparams` as an example, execute the following command to convert ```shell python3.7 tools/export_model.py \ -c ppcls/configs/reid/strong_baseline/softmax_triplet_with_center.yaml \ -o Global.pretrained_model="output/RecModel/latest" \ - -o Global.save_inference_dir="./deploy/reid_srong_baseline_softmax_with_center" + -o Global.save_inference_dir="./deploy/softmax_triplet_with_center_infer" ``` - Or download and unzip the inference model we provide ```shell cd PaddleClas/deploy - wget https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/reid_srong_baseline_softmax_with_center.tar - tar xf reid_srong_baseline_softmax_with_center.tar + wget https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/softmax_triplet_with_center_infer.tar + tar xf softmax_triplet_with_center_infer.tar cd ../ ``` -###### 2.1.6.2 Inference based on Python prediction engine +##### 3.1.2 Inference based on Python prediction engine - 1. Modify `PaddleClas/deploy/configs/inference_rec.yaml`. Change the field after `infer_imgs:` to any image path under the query folder in Market1501 (the code below uses the image path of `0294_c1s1_066631_00.jpg`); change the field after `rec_inference_model_dir:` to the extracted one reid_srong_baseline_softmax_with_center folder path; change the preprocessing configuration under the `transform_ops` field to the preprocessing configuration under `Eval.Query.dataset` in `softmax_triplet_with_center.yaml`. As follows + 1. Modify `PaddleClas/deploy/configs/inference_rec.yaml`. Change the field after `infer_imgs:` to any image path under the query folder in Market1501 (the configuration below uses the path of the `0294_c1s1_066631_00.jpg` image); change the field after `rec_inference_model_dir:` to extract it softmax_triplet_with_center_infer folder path; change the preprocessing configuration under the `transform_ops` field to the preprocessing configuration under `Eval.Query.dataset` in `softmax_triplet_with_center.yaml`. As follows ```yaml Global: infer_imgs: "../dataset/market1501/Market-1501-v15.09.15/query/0294_c1s1_066631_00.jpg" - rec_inference_model_dir: "./reid_srong_baseline_softmax_with_center" + rec_inference_model_dir: "./softmax_triplet_with_center_infer" batch_size: 1 use_gpu: False enable_mkldnn: True @@ -209,44 +234,43 @@ You can choose to use the model file saved during the training process to conver 3. Check the output result, the actual result is a vector of length 2048, which represents the feature vector obtained after the input image is transformed by the model - ```shell + ```log 0294_c1s1_066631_00.jpg: [ 0.01806974 0.00476423 -0.00508293 ... 0.03925538 0.00377574 -0.00849029] ``` The output vector for inference is stored in the `result_dict` variable in [predict_rec.py](../../../deploy/python/predict_rec.py#L134-L135). - 4. Batch prediction - Change the path after `infer_imgs:` in the configuration file to a folder, such as `../dataset/market1501/Market-1501-v15.09.15/query`, it will predict and output all images under query. Feature vector. + 4. For batch prediction, change the path after `infer_imgs:` in the configuration file to a folder, such as `../dataset/market1501/Market-1501-v15.09.15/query`, it will predict and output The feature vector of all images under query. -###### 2.1.6.3 Inference based on C++ prediction engine +##### 3.1.3 Inference based on C++ prediction engine -PaddleClas provides an example of inference based on the C++ prediction engine, you can refer to [Server-side C++ prediction](../inference_deployment/cpp_deploy_en.md) to complete the corresponding inference deployment. If you are using the Windows platform, you can refer to the Visual Studio 2019 Community CMake Compilation Guide to complete the corresponding prediction library compilation and model prediction work. +PaddleClas provides an example of inference based on C++ prediction engine, you can refer to [C++ prediction](../inference_deployment/cpp_deploy_en.md) to complete the corresponding inference deployment. If you are using the Windows platform, you can refer to the Visual Studio 2019 Community CMake Compilation Guide to complete the corresponding prediction library compilation and model prediction work. -##### 2.1.7 Service deployment +##### 3.2 Service Deployment Paddle Serving provides high-performance, flexible and easy-to-use industrial-grade online inference services. Paddle Serving supports RESTful, gRPC, bRPC and other protocols, and provides inference solutions in a variety of heterogeneous hardware and operating system environments. For more introduction to Paddle Serving, please refer to the Paddle Serving code repository. -PaddleClas provides an example of model serving deployment based on Paddle Serving. You can refer to [Model serving deployment](../inference_deployment/paddle_serving_deploy_en.md) to complete the corresponding deployment. +PaddleClas provides an example of model serving deployment based on Paddle Serving. You can refer to [Model serving deployment](../inference_deployment/paddle_serving_deploy_en.md) to complete the corresponding deployment work. -##### 2.1.8 Device side deployment +##### 3.3 Lite deployment -Paddle Lite is a high-performance, lightweight, flexible and easily extensible deep learning inference framework, positioned to support multiple hardware platforms including mobile, embedded and server. For more introduction to Paddle Lite, please refer to the Paddle Lite code repository. +Paddle Lite is a high-performance, lightweight, flexible and easily extensible deep learning inference framework, positioned to support mobileMultiple hardware platforms including client, embedded and server. For more introduction to Paddle Lite, please refer to the Paddle Lite code repository. PaddleClas provides an example of deploying models based on Paddle Lite. You can refer to [Deployment](../inference_deployment/paddle_lite_deploy_en.md) to complete the corresponding deployment. -##### 2.1.9 Paddle2ONNX Model Conversion and Prediction +##### 3.4 Paddle2ONNX model conversion and prediction -Paddle2ONNX supports converting PaddlePaddle model format to ONNX model format. The deployment of Paddle models to various inference engines can be completed through ONNX, including TensorRT/OpenVINO/MNN/TNN/NCNN, and other inference engines or hardware that support the ONNX open source format. For more information about Paddle2ONNX, please refer to the Paddle2ONNX code repository. +Paddle2ONNX supports converting PaddlePaddle model format to ONNX model format. The deployment of Paddle models to various inference engines can be completed through ONNX, including TensorRT/OpenVINO/MNN/TNN/NCNN, as well as other inference engines or hardware that support the ONNX open source format. For more information about Paddle2ONNX, please refer to the Paddle2ONNX code repository. PaddleClas provides an example of converting an inference model to an ONNX model and making inference prediction based on Paddle2ONNX. You can refer to [Paddle2ONNX model conversion and prediction](../../../deploy/paddle2onnx/readme.md) to complete the corresponding deployment work. -### 3. Summary +### 4. Summary -#### 3.1 Method summary and comparison +#### 4.1 Method summary and comparison The above algorithm can be quickly migrated to most ReID models, which can further improve the performance of ReID models. -#### 3.2 Usage advice/FAQ +#### 4.2 Usage advice/FAQ The Market1501 dataset is relatively small, so you can try to train multiple times to get the highest accuracy. @@ -254,5 +278,5 @@ The Market1501 dataset is relatively small, so you can try to train multiple tim 1. [Bag of Tricks and A Strong Baseline for Deep Person Re-identification](https://openaccess.thecvf.com/content_CVPRW_2019/papers/TRMTMCT/Luo_Bag_of_Tricks_and_a_Strong_Baseline_for_Deep_Person_CVPRW_2019_paper.pdf) 2. [michuanhaohao/reid-strong-baseline](https://github.com/michuanhaohao/reid-strong-baseline) -3. [Pedestrian Re-ID dataset Market1501Data set _star_function's blog - CSDN blog _market1501 data set](https://blog.csdn.net/qq_39220334/article/details/121470106) +3. [Pedestrian Re-ID dataset Market1501 dataset _star_function blog-CSDN blog _market1501 dataset](https://blog.csdn.net/qq_39220334/article/details/121470106) 4. [Deep Learning for Person Re-identification: A Survey and Outlook](https://arxiv.org/abs/2001.04193) diff --git a/docs/zh_CN/algorithm_introduction/reid.md b/docs/zh_CN/algorithm_introduction/reid.md index 42d069329..7a2702a32 100644 --- a/docs/zh_CN/algorithm_introduction/reid.md +++ b/docs/zh_CN/algorithm_introduction/reid.md @@ -11,22 +11,23 @@ - [2.1.2 精度指标](#212-精度指标) - [2.1.3 数据准备](#213-数据准备) - [2.1.4 模型训练](#214-模型训练) - - [2.1.5 模型评估](#215-模型评估) - - [2.1.6 模型推理部署](#216-模型推理部署) - - [2.1.6.1 推理模型准备](#2161-推理模型准备) - - [2.1.6.2 基于 Python 预测引擎推理](#2162-基于-python-预测引擎推理) - - [2.1.6.3 基于 C++ 预测引擎推理](#2163-基于-c-预测引擎推理) - - [2.1.7 服务化部署](#217-服务化部署) - - [2.1.8 端侧部署](#218-端侧部署) - - [2.1.9 Paddle2ONNX 模型转换与预测](#219-paddle2onnx-模型转换与预测) -- [3. 总结](#3-总结) - - [3.1 方法总结与对比](#31-方法总结与对比) - - [3.2 使用建议/FAQ](#32-使用建议faq) +- [3. 模型评估与推理部署](#3-模型评估与推理部署) + - [3.1 模型评估](#31-模型评估) + - [3.1 模型推理与部署](#31-模型推理与部署) + - [3.1.1 推理模型准备](#311-推理模型准备) + - [3.1.2 基于 Python 预测引擎推理](#312-基于-python-预测引擎推理) + - [3.1.3 基于 C++ 预测引擎推理](#313-基于-c-预测引擎推理) + - [3.2 服务化部署](#32-服务化部署) + - [3.3 端侧部署](#33-端侧部署) + - [3.4 Paddle2ONNX 模型转换与预测](#34-paddle2onnx-模型转换与预测) +- [4. 总结](#4-总结) + - [4.1 方法总结与对比](#41-方法总结与对比) + - [4.2 使用建议/FAQ](#42-使用建议faq) - [4. 参考资料](#4-参考资料) ### 1. 算法/应用场景简介 -行人重识别(Person re-identification)也称行人再识别,是利用[计算机视觉](https://baike.baidu.com/item/计算机视觉/2803351)技术判断[图像](https://baike.baidu.com/item/图像/773234)或者视频序列中是否存在特定行人的技术。广泛被认为是一个[图像检索](https://baike.baidu.com/item/图像检索/1150910)的子问题。给定一个监控行人图像,检索跨设备下的该行人图像。旨在弥补固定的摄像头的视觉局限,并可与[行人检测](https://baike.baidu.com/item/行人检测/20590256)/行人跟踪技术相结合,可广泛应用于[智能视频监控](https://baike.baidu.com/item/智能视频监控/10717227)、智能安保等领域。 +行人重识别(Person re-identification)也称行人再识别,是利用计算机视觉技术判断图像或者视频序列中是否存在特定行人的技术。广泛被认为是一个图像检索的子问题。给定一个监控行人图像,检索跨设备下的该行人图像。旨在弥补固定的摄像头的视觉局限,并可与行人检测/行人跟踪技术相结合,可广泛应用于智能视频监控、智能安保等领域。 常见的行人重识别方法通过特征提取模块来提取输入图片的局部/全局、单粒度/多粒度特征,再经过融合模块得到一个高维的特征向量。在训练时使用分类头将该特征向量转换成属于每个类别的概率从而以分类任务的方式来优化特征提取模型;在测试或推理时直接将高维的特征向量作为图片描述向量在检索向量库中进行检索,以得到检索结果。而ReID strong-baseline算法则是提出了多个有效优化训练与检索的方法来提升整体模型性能。 @@ -55,11 +56,11 @@ 以下表格总结了复现的ReID strong-baseline的3种配置在 Market1501 数据集上的精度指标, -| 配置文件 | recall@1 | mAP | 参考recall@1 | 参考mAP | -| ------------------------ | -------- | ----- | ------------ | ------- | -| baseline.yaml | 88.21 | 74.12 | 87.7 | 74.0 | -| softmax.yaml | 94.18 | 85.76 | 94.1 | 85.7 | -| softmax_with_center.yaml | 94.19 | 85.80 | 94.1 | 85.7 | +| 配置文件 | recall@1 | mAP | 参考recall@1 | 参考mAP | 预训练模型下载地址 | inference模型下载地址 | +| -------------------------------- | -------- | ----- | ------------ | ------- | --------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | +| baseline.yaml | 88.45 | 74.37 | 87.7 | 74.0 | [下载链接](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/baseline_pretrained.pdparams) | [下载链接](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/baseline_infer.tar) | +| softmax_triplet.yaml | 94.29 | 85.57 | 94.1 | 85.7 | [下载链接](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/softmax_triplet_pretrained.pdparams) | [下载链接](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/softmax_triplet_infer.tar) | +| softmax_triplet_with_center.yaml | 94.50 | 85.82 | 94.5 | 85.9 | [下载链接](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/softmax_triplet_with_center_pretrained.pdparams) | [下载链接](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/softmax_triplet_with_center_infer.tar) | 注:上述参考指标由使用作者开源的代码在我们的设备上训练多次得到,由于系统环境、torch版本、CUDA版本不同等原因,与作者提供的指标可能存在略微差异。 @@ -72,15 +73,15 @@ ```shell PaddleClas/dataset/market1501 └── Market-1501-v15.09.15/ - ├── bounding_box_test/ - ├── bounding_box_train/ + ├── bounding_box_test/ # gallery集图片 + ├── bounding_box_train/ # 训练集图片 ├── gt_bbox/ ├── gt_query/ - ├── query/ + ├── query/ # query集图片 ├── generate_anno.py - ├── bounding_box_test.txt - ├── bounding_box_train.txt - ├── query.txt + ├── bounding_box_test.txt # gallery集路径 + ├── bounding_box_train.txt # 训练集路径 + ├── query.txt # query集路径 └── readme.txt ``` @@ -88,17 +89,38 @@ 1. 执行以下命令开始训练 + 单卡训练: ```shell python3.7 tools/train.py -c ./ppcls/configs/reid/strong_baseline/softmax_triplet_with_center.yaml ``` + 多卡训练: + + 多卡训练需修改训练配置的采样器字段以适配分布式训练,如下所示: + ```yaml + sampler: + name: PKSampler + batch_size: 64 + sample_per_id: 4 + drop_last: False + sample_method: id_avg_prob + shuffle: True + ``` + 然后执行以下命令: + ```shell + export CUDA_VISIBLE_DEVICES=0,1,2,3 + python3.7 -m paddle.distributed.launch --gpus="0,1,2,3" tools/train.py \ + -c ./ppcls/configs/reid/strong_baseline/softmax_triplet_with_center.yaml + ``` 注:单卡训练大约需要1个小时。 2. 查看训练日志和保存的模型参数文件 训练过程中会在屏幕上实时打印loss等指标信息,同时会保存日志文件`train.log`、模型参数文件`*.pdparams`、优化器参数文件`*.pdopt`等内容到`Global.output_dir`指定的文件夹下,默认在`PaddleClas/output/RecModel/`文件夹下。 -##### 2.1.5 模型评估 +### 3. 模型评估与推理部署 + +#### 3.1 模型评估 准备用于评估的`*.pdparams`模型参数文件,可以使用训练好的模型,也可以使用[2.1.4 模型训练](#214-模型训练)中保存的模型。 @@ -110,19 +132,19 @@ -o Global.pretrained_model="./output/RecModel/latest" ``` -- 以训练好的模型为例,下载 [reid_strong_baseline_softmax_with_center.epoch_120.pdparams](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/reid_strong_baseline_softmax_with_center.epoch_120.pdparams) 到 `PaddleClas/pretrained_models` 文件夹中,执行如下命令即可进行评估。 +- 以训练好的模型为例,下载 [softmax_triplet_with_center_pretrained.pdparams](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/softmax_triplet_with_center_pretrained.pdparams) 到 `PaddleClas/pretrained_models` 文件夹中,执行如下命令即可进行评估。 ```shell # 下载模型 cd PaddleClas mkdir pretrained_models cd pretrained_models - wget https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/reid_strong_baseline_softmax_with_center.epoch_120.pdparams + wget https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/softmax_triplet_with_center_pretrained.pdparams cd .. # 评估 python3.7 tools/eval.py \ -c ppcls/configs/reid/strong_baseline/softmax_triplet_with_center.yaml \ - -o Global.pretrained_model="pretrained_models/reid_strong_baseline_softmax_with_center.epoch_120" + -o Global.pretrained_model="pretrained_models/softmax_triplet_with_center_pretrained" ``` 注:`pretrained_model` 后填入的地址不需要加 `.pdparams` 后缀,在程序运行时会自动补上。 @@ -130,6 +152,8 @@ ```log ... ... + ppcls INFO: unique_endpoints {''} + ppcls INFO: Found /root/.paddleclas/weights/resnet50-19c8e357_torch2paddle.pdparams ppcls INFO: gallery feature calculation process: [0/125] ppcls INFO: gallery feature calculation process: [20/125] ppcls INFO: gallery feature calculation process: [40/125] @@ -142,43 +166,47 @@ ppcls INFO: query feature calculation process: [20/27] ppcls INFO: Build query done, all feat shape: [3368, 2048], begin to eval.. ppcls INFO: re_ranking=False - ppcls INFO: [Eval][Epoch 0][Avg]recall1: 0.94270, recall5: 0.98189, mAP: 0.85799 + ppcls INFO: [Eval][Epoch 0][Avg]recall1: 0.94507, recall5: 0.98248, mAP: 0.85827 ``` - 默认评估日志保存在`PaddleClas/output/RecModel/eval.log`中,可以看到我们提供的 `reid_strong_baseline_softmax_with_center.epoch_120.pdparams` 模型在 Market1501 数据集上的评估指标为recall@1=0.94270,recall@5=0.98189,mAP=0.85799 + 默认评估日志保存在`PaddleClas/output/RecModel/eval.log`中,可以看到我们提供的 `softmax_triplet_with_center_pretrained.pdparams` 模型在 Market1501 数据集上的评估指标为recall@1=0.94507,recall@5=0.98248,mAP=0.85827 -##### 2.1.6 模型推理部署 +#### 3.1 模型推理与部署 -###### 2.1.6.1 推理模型准备 -可以选择使用训练过程中保存的模型文件转换成 inference 模型并推理,或者使用我们提供的转换好的 inference 模型直接进行推理 - - 将训练过程中保存的模型文件转换成 inference 模型,同样以`latest.pdparams`为例,执行以下命令进行转换 +##### 3.1.1 推理模型准备 + +可以将训练过程中保存的模型文件转换成 inference 模型并推理,或者使用我们提供的转换好的 inference 模型直接进行推理 + - 将训练过程中保存的模型文件转换成 inference 模型,同样以 `latest.pdparams` 为例,执行以下命令进行转换 ```shell python3.7 tools/export_model.py \ -c ppcls/configs/reid/strong_baseline/softmax_triplet_with_center.yaml \ -o Global.pretrained_model="output/RecModel/latest" \ - -o Global.save_inference_dir="./deploy/reid_srong_baseline_softmax_with_center" + -o Global.save_inference_dir="./deploy/softmax_triplet_with_center_infer" ``` - 或者下载并解压我们提供的 inference 模型 ```shell cd PaddleClas/deploy - wget https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/reid_srong_baseline_softmax_with_center.tar - tar xf reid_srong_baseline_softmax_with_center.tar + wget https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/softmax_triplet_with_center_infer.tar + tar xf softmax_triplet_with_center_infer.tar cd ../ ``` -###### 2.1.6.2 基于 Python 预测引擎推理 +##### 3.1.2 基于 Python 预测引擎推理 - 1. 修改 `PaddleClas/deploy/configs/inference_rec.yaml`。将 `infer_imgs:` 后的字段改为 Market1501 中 query 文件夹下的任意一张图片路径(下方配置使用的是`0294_c1s1_066631_00.jpg`图片的路径);将 `rec_inference_model_dir:` 后的字段改为解压出来的 reid_srong_baseline_softmax_with_center 文件夹路径;将 `transform_ops` 字段下的预处理配置改为 `softmax_triplet_with_center.yaml` 中`Eval.Query.dataset` 下的预处理配置。如下所示 + 1. 修改 `PaddleClas/deploy/configs/inference_rec.yaml` + - 将 `infer_imgs:` 后的路径段改为 Market1501 中 query 文件夹下的任意一张图片路径(下方配置使用的是`0294_c1s1_066631_00.jpg`图片的路径) + - 将 `rec_inference_model_dir:` 后的字段改为解压出来的 softmax_triplet_with_center_infer 文件夹路径 + - 将 `transform_ops:` 字段下的预处理配置改为 `softmax_triplet_with_center.yaml` 中`Eval.Query.dataset` 下的预处理配置 ```yaml Global: infer_imgs: "../dataset/market1501/Market-1501-v15.09.15/query/0294_c1s1_066631_00.jpg" - rec_inference_model_dir: "./reid_srong_baseline_softmax_with_center" + rec_inference_model_dir: "./softmax_triplet_with_center_infer" batch_size: 1 use_gpu: False enable_mkldnn: True cpu_num_threads: 10 - enable_benchmark: True + enable_benchmark: False use_fp16: False ir_optim: True use_tensorrt: False @@ -209,43 +237,43 @@ 3. 查看输出结果,实际结果为一个长度2048的向量,表示输入图片经过模型转换后得到的特征向量 - ```shell + ```log 0294_c1s1_066631_00.jpg: [ 0.01806974 0.00476423 -0.00508293 ... 0.03925538 0.00377574 -0.00849029] ``` 推理时的输出向量储存在[predict_rec.py](../../../deploy/python/predict_rec.py#L134-L135)的`result_dict`变量中。 - 4. 批量预测,将配置文件中`infer_imgs:`后的路径改为为文件夹即可,如`../dataset/market1501/Market-1501-v15.09.15/query`,则会预测并输出出query下所有图片的特征向量。 + 4. 批量预测,将配置文件中`infer_imgs:`后的路径改为为文件夹即可,如`../dataset/market1501/Market-1501-v15.09.15/query`,会预测并逐个输出query下所有图片的特征向量。 -###### 2.1.6.3 基于 C++ 预测引擎推理 +##### 3.1.3 基于 C++ 预测引擎推理 PaddleClas 提供了基于 C++ 预测引擎推理的示例,您可以参考[服务器端 C++ 预测](../inference_deployment/cpp_deploy.md)来完成相应的推理部署。如果您使用的是 Windows 平台,可以参考基于 Visual Studio 2019 Community CMake 编译指南完成相应的预测库编译和模型预测工作。 -##### 2.1.7 服务化部署 +##### 3.2 服务化部署 Paddle Serving 提供高性能、灵活易用的工业级在线推理服务。Paddle Serving 支持 RESTful、gRPC、bRPC 等多种协议,提供多种异构硬件和多种操作系统环境下推理解决方案。更多关于Paddle Serving 的介绍,可以参考Paddle Serving 代码仓库。 PaddleClas 提供了基于 Paddle Serving 来完成模型服务化部署的示例,您可以参考[模型服务化部署](../inference_deployment/paddle_serving_deploy.md)来完成相应的部署工作。 -##### 2.1.8 端侧部署 +##### 3.3 端侧部署 Paddle Lite 是一个高性能、轻量级、灵活性强且易于扩展的深度学习推理框架,定位于支持包括移动端、嵌入式以及服务器端在内的多硬件平台。更多关于 Paddle Lite 的介绍,可以参考Paddle Lite 代码仓库。 PaddleClas 提供了基于 Paddle Lite 来完成模型端侧部署的示例,您可以参考[端侧部署](../inference_deployment/paddle_lite_deploy.md)来完成相应的部署工作。 -##### 2.1.9 Paddle2ONNX 模型转换与预测 +##### 3.4 Paddle2ONNX 模型转换与预测 Paddle2ONNX 支持将 PaddlePaddle 模型格式转化到 ONNX 模型格式。通过 ONNX 可以完成将 Paddle 模型到多种推理引擎的部署,包括TensorRT/OpenVINO/MNN/TNN/NCNN,以及其它对 ONNX 开源格式进行支持的推理引擎或硬件。更多关于 Paddle2ONNX 的介绍,可以参考Paddle2ONNX 代码仓库。 PaddleClas 提供了基于 Paddle2ONNX 来完成 inference 模型转换 ONNX 模型并作推理预测的示例,您可以参考[Paddle2ONNX 模型转换与预测](../../../deploy/paddle2onnx/readme.md)来完成相应的部署工作。 -### 3. 总结 +### 4. 总结 -#### 3.1 方法总结与对比 +#### 4.1 方法总结与对比 上述算法能快速地迁移至多数的ReID模型中,能进一步提升ReID模型的性能。 -#### 3.2 使用建议/FAQ +#### 4.2 使用建议/FAQ Market1501 数据集比较小,可以尝试训练多次取最高精度。 From e1800e0025803a0c72dfaad5dfb8186d10bf1d8a Mon Sep 17 00:00:00 2001 From: HydrogenSulfate <490868991@qq.com> Date: Thu, 23 Jun 2022 16:29:33 +0800 Subject: [PATCH 7/9] add comment in preprocess.py and correct contents in docs --- deploy/python/preprocess.py | 2 ++ docs/en/algorithm_introduction/reid.md | 38 +++++++++++------------ docs/zh_CN/algorithm_introduction/reid.md | 38 +++++++++++------------ 3 files changed, 40 insertions(+), 38 deletions(-) diff --git a/deploy/python/preprocess.py b/deploy/python/preprocess.py index aa66492a3..695270833 100644 --- a/deploy/python/preprocess.py +++ b/deploy/python/preprocess.py @@ -176,8 +176,10 @@ class ResizeImage(object): def __call__(self, img): if isinstance(img, np.ndarray): + # numpy input img_h, img_w = img.shape[:2] else: + # PIL image input img_w, img_h = img.size if self.resize_short is not None: diff --git a/docs/en/algorithm_introduction/reid.md b/docs/en/algorithm_introduction/reid.md index 2f8d3c28b..597691337 100644 --- a/docs/en/algorithm_introduction/reid.md +++ b/docs/en/algorithm_introduction/reid.md @@ -13,13 +13,13 @@ English | [简体中文](../../zh_CN/algorithm_introduction/reid.md) - [2.1.4 Model training](#214-model-training) - [3. Model evaluation and inference deployment](#3-model-evaluation-and-inference-deployment) - [3.1 Model Evaluation](#31-model-evaluation) - - [3.1 Model Inference and Deployment](#31-model-inference-and-deployment) - - [3.1.1 Inference model preparation](#311-inference-model-preparation) - - [3.1.2 Inference based on Python prediction engine](#312-inference-based-on-python-prediction-engine) - - [3.1.3 Inference based on C++ prediction engine](#313-inference-based-on-c-prediction-engine) - - [3.2 Service Deployment](#32-service-deployment) - - [3.3 Device side deployment](#33-device-side-deployment) - - [3.4 Paddle2ONNX model conversion and prediction](#34-paddle2onnx-model-conversion-and-prediction) + - [3.2 Model Inference and Deployment](#32-model-inference-and-deployment) + - [3.2.1 Inference model preparation](#321-inference-model-preparation) + - [3.2.2 Inference based on Python prediction engine](#322-inference-based-on-python-prediction-engine) + - [3.2.3 Inference based on C++ prediction engine](#323-inference-based-on-c-prediction-engine) + - [3.3 Service Deployment](#33-service-deployment) + - [3.4 Lite deployment](#34-lite-deployment) + - [3.5 Paddle2ONNX model conversion and prediction](#35-paddle2onnx-model-conversion-and-prediction) - [4. Summary](#4-summary) - [4.1 Method summary and comparison](#41-method-summary-and-comparison) - [4.2 Usage advice/FAQ](#42-usage-advicefaq) @@ -56,11 +56,11 @@ Based on the commonly used person re-identification model based on ResNet50, the The following table summarizes the accuracy metrics of the 3 configurations of the recurring ReID strong-baseline on the Market1501 dataset, -| Configuration file | recall@1 | mAP | Refer to recall@1 | Refer to mAP | Pre-trained model download | Inference Model Download Address | -| -------------------------------- | -------- | ----- | ----------------- | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | -| baseline.yaml | 88.45 | 74.37 | 87.7 | 74.0 | [Download link](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/baseline_pretrained.pdparams) | [Download link](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/baseline_infer.tar) | -| softmax_triplet.yaml | 94.29 | 85.57 | 94.1 | 85.7 | [Download link](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/softmax_triplet_pretrained.pdparams) | [Download link](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/softmax_triplet_infer.tar) | -| softmax_triplet_with_center.yaml | 94.50 | 85.82 | 94.5 | 85.9 | [Download link](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/softmax_triplet_with_center_pretrained.pdparams) | [Download link](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/softmax_triplet_with_center_infer.tar) | +| Configuration file | recall@1(\%) | mAP(\%) | Refer to recall@1(\%) | Refer to mAP(\%) | Pre-trained model download | Inference Model Download Address | +| -------------------------------- | ------------ | ------- | --------------------- | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | +| baseline.yaml | 88.45 | 74.37 | 87.7 | 74.0 | [Download link](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/baseline_pretrained.pdparams) | [Download link](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/baseline_infer.tar) | +| softmax_triplet.yaml | 94.29 | 85.57 | 94.1 | 85.7 | [Download link](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/softmax_triplet_pretrained.pdparams) | [Download link](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/softmax_triplet_infer.tar) | +| softmax_triplet_with_center.yaml | 94.50 | 85.82 | 94.5 | 85.9 | [Download link](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/softmax_triplet_with_center_pretrained.pdparams) | [Download link](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/softmax_triplet_with_center_infer.tar) | Note: The above reference indicators are obtained by using the author's open source code to train on our equipment for many times. Due to different system environments, torch versions, and CUDA versions, there may be slight differences with the indicators provided by the author. @@ -170,9 +170,9 @@ Prepare the `*.pdparams` model parameter file for evaluation. You can use the tr ``` The default evaluation log is saved in `PaddleClas/output/RecModel/eval.log`. You can see that the evaluation metrics of the `softmax_triplet_with_center_pretrained.pdparams` model we provided on the Market1501 dataset are recall@1=0.94507, recall@5 =0.98248, mAP=0.85827 -#### 3.1 Model Inference and Deployment +#### 3.2 Model Inference and Deployment -##### 3.1.1 Inference model preparation +##### 3.2.1 Inference model preparation You can convert the model file saved during training into an inference model and inference, or use the converted inference model we provide for direct inference - Convert the model file saved during the training process to an inference model, also take `latest.pdparams` as an example, execute the following command to convert @@ -191,7 +191,7 @@ You can convert the model file saved during training into an inference model and cd ../ ``` -##### 3.1.2 Inference based on Python prediction engine +##### 3.2.2 Inference based on Python prediction engine 1. Modify `PaddleClas/deploy/configs/inference_rec.yaml`. Change the field after `infer_imgs:` to any image path under the query folder in Market1501 (the configuration below uses the path of the `0294_c1s1_066631_00.jpg` image); change the field after `rec_inference_model_dir:` to extract it softmax_triplet_with_center_infer folder path; change the preprocessing configuration under the `transform_ops` field to the preprocessing configuration under `Eval.Query.dataset` in `softmax_triplet_with_center.yaml`. As follows @@ -242,23 +242,23 @@ You can convert the model file saved during training into an inference model and 4. For batch prediction, change the path after `infer_imgs:` in the configuration file to a folder, such as `../dataset/market1501/Market-1501-v15.09.15/query`, it will predict and output The feature vector of all images under query. -##### 3.1.3 Inference based on C++ prediction engine +##### 3.2.3 Inference based on C++ prediction engine PaddleClas provides an example of inference based on C++ prediction engine, you can refer to [C++ prediction](../inference_deployment/cpp_deploy_en.md) to complete the corresponding inference deployment. If you are using the Windows platform, you can refer to the Visual Studio 2019 Community CMake Compilation Guide to complete the corresponding prediction library compilation and model prediction work. -##### 3.2 Service Deployment +#### 3.3 Service Deployment Paddle Serving provides high-performance, flexible and easy-to-use industrial-grade online inference services. Paddle Serving supports RESTful, gRPC, bRPC and other protocols, and provides inference solutions in a variety of heterogeneous hardware and operating system environments. For more introduction to Paddle Serving, please refer to the Paddle Serving code repository. PaddleClas provides an example of model serving deployment based on Paddle Serving. You can refer to [Model serving deployment](../inference_deployment/paddle_serving_deploy_en.md) to complete the corresponding deployment work. -##### 3.3 Lite deployment +#### 3.4 Lite deployment Paddle Lite is a high-performance, lightweight, flexible and easily extensible deep learning inference framework, positioned to support mobileMultiple hardware platforms including client, embedded and server. For more introduction to Paddle Lite, please refer to the Paddle Lite code repository. PaddleClas provides an example of deploying models based on Paddle Lite. You can refer to [Deployment](../inference_deployment/paddle_lite_deploy_en.md) to complete the corresponding deployment. -##### 3.4 Paddle2ONNX model conversion and prediction +#### 3.5 Paddle2ONNX model conversion and prediction Paddle2ONNX supports converting PaddlePaddle model format to ONNX model format. The deployment of Paddle models to various inference engines can be completed through ONNX, including TensorRT/OpenVINO/MNN/TNN/NCNN, as well as other inference engines or hardware that support the ONNX open source format. For more information about Paddle2ONNX, please refer to the Paddle2ONNX code repository. diff --git a/docs/zh_CN/algorithm_introduction/reid.md b/docs/zh_CN/algorithm_introduction/reid.md index 7a2702a32..cc4b66d1a 100644 --- a/docs/zh_CN/algorithm_introduction/reid.md +++ b/docs/zh_CN/algorithm_introduction/reid.md @@ -13,13 +13,13 @@ - [2.1.4 模型训练](#214-模型训练) - [3. 模型评估与推理部署](#3-模型评估与推理部署) - [3.1 模型评估](#31-模型评估) - - [3.1 模型推理与部署](#31-模型推理与部署) - - [3.1.1 推理模型准备](#311-推理模型准备) - - [3.1.2 基于 Python 预测引擎推理](#312-基于-python-预测引擎推理) - - [3.1.3 基于 C++ 预测引擎推理](#313-基于-c-预测引擎推理) - - [3.2 服务化部署](#32-服务化部署) - - [3.3 端侧部署](#33-端侧部署) - - [3.4 Paddle2ONNX 模型转换与预测](#34-paddle2onnx-模型转换与预测) + - [3.2 模型推理](#32-模型推理) + - [3.2.1 推理模型准备](#321-推理模型准备) + - [3.2.2 基于 Python 预测引擎推理](#322-基于-python-预测引擎推理) + - [3.2.3 基于 C++ 预测引擎推理](#323-基于-c-预测引擎推理) + - [3.3 服务化部署](#33-服务化部署) + - [3.4 端侧部署](#34-端侧部署) + - [3.5 Paddle2ONNX 模型转换与预测](#35-paddle2onnx-模型转换与预测) - [4. 总结](#4-总结) - [4.1 方法总结与对比](#41-方法总结与对比) - [4.2 使用建议/FAQ](#42-使用建议faq) @@ -56,11 +56,11 @@ 以下表格总结了复现的ReID strong-baseline的3种配置在 Market1501 数据集上的精度指标, -| 配置文件 | recall@1 | mAP | 参考recall@1 | 参考mAP | 预训练模型下载地址 | inference模型下载地址 | -| -------------------------------- | -------- | ----- | ------------ | ------- | --------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | -| baseline.yaml | 88.45 | 74.37 | 87.7 | 74.0 | [下载链接](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/baseline_pretrained.pdparams) | [下载链接](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/baseline_infer.tar) | -| softmax_triplet.yaml | 94.29 | 85.57 | 94.1 | 85.7 | [下载链接](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/softmax_triplet_pretrained.pdparams) | [下载链接](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/softmax_triplet_infer.tar) | -| softmax_triplet_with_center.yaml | 94.50 | 85.82 | 94.5 | 85.9 | [下载链接](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/softmax_triplet_with_center_pretrained.pdparams) | [下载链接](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/softmax_triplet_with_center_infer.tar) | +| 配置文件 | recall@1(\%) | mAP(\%) | 参考recall@1(\%) | 参考mAP(\%) | 预训练模型下载地址 | inference模型下载地址 | +| -------------------------------- | ------------ | ------- | ---------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | +| baseline.yaml | 88.45 | 74.37 | 87.7 | 74.0 | [下载链接](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/baseline_pretrained.pdparams) | [下载链接](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/baseline_infer.tar) | +| softmax_triplet.yaml | 94.29 | 85.57 | 94.1 | 85.7 | [下载链接](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/softmax_triplet_pretrained.pdparams) | [下载链接](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/softmax_triplet_infer.tar) | +| softmax_triplet_with_center.yaml | 94.50 | 85.82 | 94.5 | 85.9 | [下载链接](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/softmax_triplet_with_center_pretrained.pdparams) | [下载链接](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/softmax_triplet_with_center_infer.tar) | 注:上述参考指标由使用作者开源的代码在我们的设备上训练多次得到,由于系统环境、torch版本、CUDA版本不同等原因,与作者提供的指标可能存在略微差异。 @@ -170,9 +170,9 @@ ``` 默认评估日志保存在`PaddleClas/output/RecModel/eval.log`中,可以看到我们提供的 `softmax_triplet_with_center_pretrained.pdparams` 模型在 Market1501 数据集上的评估指标为recall@1=0.94507,recall@5=0.98248,mAP=0.85827 -#### 3.1 模型推理与部署 +#### 3.2 模型推理 -##### 3.1.1 推理模型准备 +##### 3.2.1 推理模型准备 可以将训练过程中保存的模型文件转换成 inference 模型并推理,或者使用我们提供的转换好的 inference 模型直接进行推理 - 将训练过程中保存的模型文件转换成 inference 模型,同样以 `latest.pdparams` 为例,执行以下命令进行转换 @@ -191,7 +191,7 @@ cd ../ ``` -##### 3.1.2 基于 Python 预测引擎推理 +##### 3.2.2 基于 Python 预测引擎推理 1. 修改 `PaddleClas/deploy/configs/inference_rec.yaml` - 将 `infer_imgs:` 后的路径段改为 Market1501 中 query 文件夹下的任意一张图片路径(下方配置使用的是`0294_c1s1_066631_00.jpg`图片的路径) @@ -245,23 +245,23 @@ 4. 批量预测,将配置文件中`infer_imgs:`后的路径改为为文件夹即可,如`../dataset/market1501/Market-1501-v15.09.15/query`,会预测并逐个输出query下所有图片的特征向量。 -##### 3.1.3 基于 C++ 预测引擎推理 +##### 3.2.3 基于 C++ 预测引擎推理 PaddleClas 提供了基于 C++ 预测引擎推理的示例,您可以参考[服务器端 C++ 预测](../inference_deployment/cpp_deploy.md)来完成相应的推理部署。如果您使用的是 Windows 平台,可以参考基于 Visual Studio 2019 Community CMake 编译指南完成相应的预测库编译和模型预测工作。 -##### 3.2 服务化部署 +#### 3.3 服务化部署 Paddle Serving 提供高性能、灵活易用的工业级在线推理服务。Paddle Serving 支持 RESTful、gRPC、bRPC 等多种协议,提供多种异构硬件和多种操作系统环境下推理解决方案。更多关于Paddle Serving 的介绍,可以参考Paddle Serving 代码仓库。 PaddleClas 提供了基于 Paddle Serving 来完成模型服务化部署的示例,您可以参考[模型服务化部署](../inference_deployment/paddle_serving_deploy.md)来完成相应的部署工作。 -##### 3.3 端侧部署 +#### 3.4 端侧部署 Paddle Lite 是一个高性能、轻量级、灵活性强且易于扩展的深度学习推理框架,定位于支持包括移动端、嵌入式以及服务器端在内的多硬件平台。更多关于 Paddle Lite 的介绍,可以参考Paddle Lite 代码仓库。 PaddleClas 提供了基于 Paddle Lite 来完成模型端侧部署的示例,您可以参考[端侧部署](../inference_deployment/paddle_lite_deploy.md)来完成相应的部署工作。 -##### 3.4 Paddle2ONNX 模型转换与预测 +#### 3.5 Paddle2ONNX 模型转换与预测 Paddle2ONNX 支持将 PaddlePaddle 模型格式转化到 ONNX 模型格式。通过 ONNX 可以完成将 Paddle 模型到多种推理引擎的部署,包括TensorRT/OpenVINO/MNN/TNN/NCNN,以及其它对 ONNX 开源格式进行支持的推理引擎或硬件。更多关于 Paddle2ONNX 的介绍,可以参考Paddle2ONNX 代码仓库。 From e2431804828b247e38b33a65d10b75e26a1875a2 Mon Sep 17 00:00:00 2001 From: HydrogenSulfate <490868991@qq.com> Date: Sat, 2 Jul 2022 23:33:25 +0800 Subject: [PATCH 8/9] update introduction and add common metrics for reid docs --- docs/en/algorithm_introduction/reid.md | 172 ++++++++++++++-------- docs/zh_CN/algorithm_introduction/reid.md | 124 ++++++++++------ 2 files changed, 189 insertions(+), 107 deletions(-) diff --git a/docs/en/algorithm_introduction/reid.md b/docs/en/algorithm_introduction/reid.md index 597691337..b69e9d0cc 100644 --- a/docs/en/algorithm_introduction/reid.md +++ b/docs/en/algorithm_introduction/reid.md @@ -2,45 +2,84 @@ English | [简体中文](../../zh_CN/algorithm_introduction/reid.md) # ReID pedestrian re-identification -## Table of contents +## Contents - [1. Introduction to algorithms/application scenarios](#1-introduction-to-algorithmsapplication-scenarios) -- [2. ReID algorithm](#2-reid-algorithm) - - [2.1 ReID strong-baseline](#21-reid-strong-baseline) - - [2.1.1 Principle introduction](#211-principle-introduction) - - [2.1.2 Accuracy Index](#212-accuracy-index) - - [2.1.3 Data Preparation](#213-data-preparation) - - [2.1.4 Model training](#214-model-training) -- [3. Model evaluation and inference deployment](#3-model-evaluation-and-inference-deployment) - - [3.1 Model Evaluation](#31-model-evaluation) - - [3.2 Model Inference and Deployment](#32-model-inference-and-deployment) - - [3.2.1 Inference model preparation](#321-inference-model-preparation) - - [3.2.2 Inference based on Python prediction engine](#322-inference-based-on-python-prediction-engine) - - [3.2.3 Inference based on C++ prediction engine](#323-inference-based-on-c-prediction-engine) - - [3.3 Service Deployment](#33-service-deployment) - - [3.4 Lite deployment](#34-lite-deployment) - - [3.5 Paddle2ONNX model conversion and prediction](#35-paddle2onnx-model-conversion-and-prediction) -- [4. Summary](#4-summary) - - [4.1 Method summary and comparison](#41-method-summary-and-comparison) - - [4.2 Usage advice/FAQ](#42-usage-advicefaq) -- [4. References](#4-references) +- [2. Common datasets and metrics](#2-common-datasets-and-metrics) + - [2.1 Common datasets](#21-common-datasets) + - [2.2 Common metric](#22-common-metric) +- [3. ReID algorithm](#3-reid-algorithm) + - [3.1 ReID strong-baseline](#31-reid-strong-baseline) + - [3.1.1 Principle introduction](#311-principle-introduction) + - [3.1.2 Accuracy metrics](#312-accuracy-metrics) + - [3.1.3 Data Preparation](#313-data-preparation) + - [3.1.4 Model training](#314-model-training) +- [4. Model evaluation and inference deployment](#4-model-evaluation-and-inference-deployment) + - [4.1 Model Evaluation](#41-model-evaluation) + - [4.2 Model Inference](#42-model-inference) + - [4.2.1 Inference model preparation](#421-inference-model-preparation) + - [4.2.2 Inference based on Python prediction engine](#422-inference-based-on-python-prediction-engine) + - [4.2.3 Inference based on C++ prediction engine](#423-inference-based-on-c-prediction-engine) + - [4.3 Service deployment](#43-service-deployment) + - [4.4 Lite deployment](#44-lite-deployment) + - [4.5 Paddle2ONNX Model Conversion and Prediction](#45-paddle2onnx-model-conversion-and-prediction) +- [5. Summary](#5-summary) + - [5.1 Method summary and comparison](#51-method-summary-and-comparison) + - [5.2 Usage advice/FAQ](#52-usage-advicefaq) +- [6. References](#6-references) ### 1. Introduction to algorithms/application scenarios -Pedestrian re-identification, also known as pedestrian re-identification, is a technology that uses computer vision technology to determine whether there is a specific pedestrian in an image or video sequence. Widely regarded as a sub-problem of image retrieval. Given a surveillance pedestrian image, retrieve the pedestrian image across devices. It is designed to make up for the visual limitations of fixed cameras, and can be combined with pedestrian detection/pedestrian tracking technology, which can be widely used in intelligent video surveillance, intelligent security and other fields. +Person re-identification (Re-ID), also known as person re-identification, has been widely studied as a cross-shot pedestrian retrieval problem. Given a pedestrian image captured by a certain camera, the goal is to determine whether the pedestrian has appeared in images captured by different cameras or in different time periods. The given pedestrian data can be a picture, a video frame, or even a text description. In recent years, the application demand of this technology in the field of public safety has been increasing, and the influence of pedestrian re-identification in intelligent monitoring technology is also increasing. + +At present, pedestrian re-identification is still a challenging task, especially the problems of different viewpoints, resolutions, illumination changes, occlusions, multi-modalities, as well as complex camera environment and background, labeling data noise, etc. There is great uncertainty. In addition, when the actual landing, the shooting camera may change, the large-scale retrieval database, the distribution shift of the data set, the unknown scene, the incremental update of the model, and the change of the clothing of the retrieval person, which also increases a lot of difficulties. + +Early work on person re-identification mainly focused on hand-designed feature extraction operators, including adding human pose features, or learning distance metric functions. With the development of deep learning technology, pedestrian recognition has also made great progress. In general, the whole process of pedestrian re-identification includes 5 steps: 1) data collection, 2) pedestrian location box annotation, 3) pedestrian category annotation, 4) model training, and 5) pedestrian retrieval (model testing). -The common person re-identification method extracts the local/global, single-granularity/multi-granularity features of the input image through the feature extraction module, and then obtains a high-dimensional feature vector through the fusion module. Use the classification head to convert the feature vector into the probability of each category during training to optimize the feature extraction model in the way of classification tasks; directly use the high-dimensional feature vector as the image description vector in the retrieval vector library during testing or inference search to get the search results. The ReID strong-baseline algorithm proposes several methods to effectively optimize training and retrieval to improve the overall model performance. -### 2. ReID algorithm +### 2. Common datasets and metrics -#### 2.1 ReID strong-baseline +#### 2.1 Common datasets + +| Dataset | #ID | #Image | #cam | +| :---------- | :----: | :----: | :---: | +| VIPeR | 632 | 1264 | 2 | +| iLIDS | 119 | 476 | 2 | +| GRID | 250 | 1275 | 2 | +| PRID2011 | 200 | 1134 | 2 | +| CUHK01 | 971 | 3884 | 2 | +| CUHK02 | 1816 | 7264 | 2 | +| CUHK03 | 1467 | 13164 | 2 | +| Market-1501 | 1501 | 32668 | 2 | +| DukeMTMC | 1404 | 36411 | 2 | +| Airport | 39902 | 39902 | 2 | +| MSMT17 | 126441 | 126441 | 2 | + +#### 2.2 Common metric + +1. CMC curve + + The formula is as follows: + $$ CMC(K)=\frac{1}{N} \sum_{i=1}^{N} \begin{cases} 1, & \text{if $label_i \in Top{K}(result_i)$} \\\\ 0, & \text{if $label_i \notin Top{K}(result_i)$} \end{cases} $$ + + Among them, $N$ is the number of query samples, and $result_i$ is the label set of the retrieval results of each query sample. According to the formula, the CMC curve can be understood as an array composed of Top1-Acc, Top2-Acc, ..., TopK-Acc , which is obviously a monotonic curve. Among them, the common Rank-1 and Top1-Acc metric refer to CMC(1) + +2. mAP + + Assuming that a query sample is used and a set of query results is returned, then according to the following formula, consider the first K query results one by one, and for each K, calculate the precision rate $Precision$ and recall rate $Recall$. + $$\begin{align} precision&=\frac{|\\{同类别图片\\} \cap \\{前K个查询结果\\}|}{|\\{前K个查询结果\\}|} \\\\ recall&=\frac{|\\{同类别图片\\} \cap \\{前K个查询结果\\}|}{|\\{同类别图片\\}|} \end{align}$$ + The obtained multiple groups (Precision, Recall) are converted into a curve graph, and the area enclosed by the curve and the coordinate axis is called Average Precision (AP), + For each sample, calculate its AP value, and then take the average to get the mAP. +### 3. ReID algorithm + +#### 3.1 ReID strong-baseline Paper source: [Bag of Tricks and A Strong Baseline for Deep Person Re-identification](https://openaccess.thecvf.com/content_CVPRW_2019/papers/TRMTMCT/Luo_Bag_of_Tricks_and_a_Strong_Baseline_for_Deep_Person_CVPRW_2019_paper.pdf) -##### 2.1.1 Principle introduction +##### 3.1.1 Principle introduction Based on the commonly used person re-identification model based on ResNet50, the author explores and summarizes the following effective and applicable optimization methods, which greatly improves the indicators on multiple person re-identification datasets. @@ -52,40 +91,40 @@ Based on the commonly used person re-identification model based on ResNet50, the 6. Center loss: Give each category a learnable cluster center, and make the intra-class features close to the cluster center during training to reduce intra-class differences and increase inter-class differences. 7. Reranking: Consider the neighbor candidates of the query image during retrieval, optimize the distance matrix according to whether the neighbor images of the candidate object also contain the query image, and finally improve the retrieval accuracy. -##### 2.1.2 Accuracy Index +##### 3.1.2 Accuracy metrics The following table summarizes the accuracy metrics of the 3 configurations of the recurring ReID strong-baseline on the Market1501 dataset, -| Configuration file | recall@1(\%) | mAP(\%) | Refer to recall@1(\%) | Refer to mAP(\%) | Pre-trained model download | Inference Model Download Address | -| -------------------------------- | ------------ | ------- | --------------------- | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | -| baseline.yaml | 88.45 | 74.37 | 87.7 | 74.0 | [Download link](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/baseline_pretrained.pdparams) | [Download link](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/baseline_infer.tar) | -| softmax_triplet.yaml | 94.29 | 85.57 | 94.1 | 85.7 | [Download link](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/softmax_triplet_pretrained.pdparams) | [Download link](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/softmax_triplet_infer.tar) | -| softmax_triplet_with_center.yaml | 94.50 | 85.82 | 94.5 | 85.9 | [Download link](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/softmax_triplet_with_center_pretrained.pdparams) | [Download link](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/softmax_triplet_with_center_infer.tar) | +| configuration file | recall@1(\%) | mAP(\%) | reference recall@1(\%) | reference mAP(\%) | pretrained model download address | inference model download address | +| ------------------ | ------------ | ------- | ---------------------- | ----------------- | --------------------------------- | -------------------------------- | +| baseline.yaml | 88.45 | 74.37 | 87.7 | 74.0 | [download link](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/baseline_pretrained.pdparams) | [ Download link](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/baseline_infer.tar) | +| softmax_triplet.yaml | 94.29 | 85.57 | 94.1 | 85.7 | [download link](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/softmax_triplet_pretrained.pdparams) | [ Download link](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/softmax_triplet_infer.tar) | +| softmax_triplet_with_center.yaml | 94.50 | 85.82 | 94.5 | 85.9 | [Download link](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/softmax_triplet_with_center_pretrained.pdparams) | [ Download link](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/softmax_triplet_with_center_infer.tar) | -Note: The above reference indicators are obtained by using the author's open source code to train on our equipment for many times. Due to different system environments, torch versions, and CUDA versions, there may be slight differences with the indicators provided by the author. +Note: The above reference indicators are obtained by using the author's open source code to train on our equipment for many times. Due to different system environment, torch version, CUDA version and other reasons, there may be slight differences with the indicators provided by the author. Next, we mainly take the `softmax_triplet_with_center.yaml` configuration and trained model file as an example to show the process of training, testing, and inference on the Market1501 dataset. -##### 2.1.3 Data Preparation +##### 3.1.3 Data Preparation Download the [Market-1501-v15.09.15.zip](https://pan.baidu.com/s/1ntIi2Op?_at_=1654142245770) dataset, extract it to `PaddleClas/dataset/`, and organize it into the following file structure : ```shell PaddleClas/dataset/market1501 └── Market-1501-v15.09.15/ - ├── bounding_box_test/ # gallery set pictures - ├── bounding_box_train/ # training set image + ├── bounding_box_test/ # gallery set pictures + ├── bounding_box_train/ # training set image ├── gt_bbox/ ├── gt_query/ - ├── query/ # query set image + ├── query/ # query set image ├── generate_anno.py - ├── bounding_box_test.txt # gallery set path - ├── bounding_box_train.txt # training set path - ├── query.txt # query set path + ├── bounding_box_test.txt # gallery set path + ├── bounding_box_train.txt # training set path + ├── query.txt # query set path └── readme.txt ``` -##### 2.1.4 Model training +##### 3.1.4 Model training 1. Execute the following command to start training @@ -96,7 +135,7 @@ Download the [Market-1501-v15.09.15.zip](https://pan.baidu.com/s/1ntIi2Op?_at_=1 Doka training: - For Doka training, you need to modify the sampler field of the training configuration as follows: + For multi-card training, you need to modify the sampler field of the training configuration to adapt to distributed training, as follows: ```yaml sampler: name: PKSampler @@ -106,7 +145,7 @@ Download the [Market-1501-v15.09.15.zip](https://pan.baidu.com/s/1ntIi2Op?_at_=1 sample_method: id_avg_prob shuffle: True ``` - Then execute the following command(example of 4 gpus below): + Then execute the following command: ```shell export CUDA_VISIBLE_DEVICES=0,1,2,3 python3.7 -m paddle.distributed.launch --gpus="0,1,2,3" tools/train.py \ @@ -118,9 +157,9 @@ Download the [Market-1501-v15.09.15.zip](https://pan.baidu.com/s/1ntIi2Op?_at_=1 During the training process, indicator information such as loss will be printed on the screen in real time, and the log file `train.log`, model parameter file `*.pdparams`, optimizer parameter file `*.pdopt` and other contents will be saved to `Global.output_dir` `Under the specified folder, the default is under the `PaddleClas/output/RecModel/` folder. -### 3. Model evaluation and inference deployment +### 4. Model evaluation and inference deployment -#### 3.1 Model Evaluation +#### 4.1 Model Evaluation Prepare the `*.pdparams` model parameter file for evaluation. You can use the trained model or the model saved in [2.1.4 Model training] (#214-model training). @@ -132,7 +171,7 @@ Prepare the `*.pdparams` model parameter file for evaluation. You can use the tr -o Global.pretrained_model="./output/RecModel/latest" ``` -- to train wellTake the model as an example, download [softmax_triplet_with_center_pretrained.pdparams](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/softmax_triplet_with_center_pretrained.pdparams) to `PaddleClas/ In the pretrained_models` folder, execute the following command to evaluate. +- Take the trained model as an example, download [softmax_triplet_with_center_pretrained.pdparams](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/softmax_triplet_with_center_pretrained.pdparams) to `PaddleClas/ In the pretrained_models` folder, execute the following command to evaluate. ```shell # download model @@ -168,11 +207,11 @@ Prepare the `*.pdparams` model parameter file for evaluation. You can use the tr ppcls INFO: re_ranking=False ppcls INFO: [Eval][Epoch 0][Avg]recall1: 0.94507, recall5: 0.98248, mAP: 0.85827 ``` - The default evaluation log is saved in `PaddleClas/output/RecModel/eval.log`. You can see that the evaluation metrics of the `softmax_triplet_with_center_pretrained.pdparams` model we provided on the Market1501 dataset are recall@1=0.94507, recall@5 =0.98248, mAP=0.85827 + The default evaluation log is saved in `PaddleClas/output/RecModel/eval.log`. You can see that the evaluation indicators of the `softmax_triplet_with_center_pretrained.pdparams` model provided by us on the Market1501 dataset are recall@1=0.94507, recall@5=0.98248 , mAP=0.85827 -#### 3.2 Model Inference and Deployment +#### 4.2 Model Inference -##### 3.2.1 Inference model preparation +##### 4.2.1 Inference model preparation You can convert the model file saved during training into an inference model and inference, or use the converted inference model we provide for direct inference - Convert the model file saved during the training process to an inference model, also take `latest.pdparams` as an example, execute the following command to convert @@ -191,9 +230,11 @@ You can convert the model file saved during training into an inference model and cd ../ ``` -##### 3.2.2 Inference based on Python prediction engine +##### 4.2.2 Inference based on Python prediction engine - 1. Modify `PaddleClas/deploy/configs/inference_rec.yaml`. Change the field after `infer_imgs:` to any image path under the query folder in Market1501 (the configuration below uses the path of the `0294_c1s1_066631_00.jpg` image); change the field after `rec_inference_model_dir:` to extract it softmax_triplet_with_center_infer folder path; change the preprocessing configuration under the `transform_ops` field to the preprocessing configuration under `Eval.Query.dataset` in `softmax_triplet_with_center.yaml`. As follows + 1. Modify `PaddleClas/deploy/configs/inference_rec.yaml`- Change the path segment after `infer_imgs:` to any image path under the query folder in Market1501 (the configuration below uses the path of the `0294_c1s1_066631_00.jpg` image) + - Change the field after `rec_inference_model_dir:` to the decompressed softmax_triplet_with_center_infer folder path + - Change the preprocessing configuration under the `transform_ops:` field to the preprocessing configuration under `Eval.Query.dataset` in `softmax_triplet_with_center.yaml` ```yaml Global: @@ -203,7 +244,7 @@ You can convert the model file saved during training into an inference model and use_gpu: False enable_mkldnn: True cpu_num_threads: 10 - enable_benchmark: True + enable_benchmark: False use_fp16: False ir_optim: True use_tensorrt: False @@ -240,43 +281,44 @@ You can convert the model file saved during training into an inference model and ``` The output vector for inference is stored in the `result_dict` variable in [predict_rec.py](../../../deploy/python/predict_rec.py#L134-L135). - 4. For batch prediction, change the path after `infer_imgs:` in the configuration file to a folder, such as `../dataset/market1501/Market-1501-v15.09.15/query`, it will predict and output The feature vector of all images under query. + 4. For batch prediction, change the path after `infer_imgs:` in the configuration file to a folder, such as `../dataset/market1501/Market-1501-v15.09.15/query`, it will predict and output queries one by one The feature vectors of all the images below. -##### 3.2.3 Inference based on C++ prediction engine +##### 4.2.3 Inference based on C++ prediction engine -PaddleClas provides an example of inference based on C++ prediction engine, you can refer to [C++ prediction](../inference_deployment/cpp_deploy_en.md) to complete the corresponding inference deployment. If you are using the Windows platform, you can refer to the Visual Studio 2019 Community CMake Compilation Guide to complete the corresponding prediction library compilation and model prediction work. +PaddleClas provides an example of inference based on the C++ prediction engine, you can refer to [Server-side C++ prediction](../inference_deployment/cpp_deploy.md) to complete the corresponding inference deployment. If you are using the Windows platform, you can refer to the Visual Studio 2019 Community CMake Compilation Guide to complete the corresponding prediction library compilation and model prediction work. -#### 3.3 Service Deployment +#### 4.3 Service deployment Paddle Serving provides high-performance, flexible and easy-to-use industrial-grade online inference services. Paddle Serving supports RESTful, gRPC, bRPC and other protocols, and provides inference solutions in a variety of heterogeneous hardware and operating system environments. For more introduction to Paddle Serving, please refer to the Paddle Serving code repository. -PaddleClas provides an example of model serving deployment based on Paddle Serving. You can refer to [Model serving deployment](../inference_deployment/paddle_serving_deploy_en.md) to complete the corresponding deployment work. +PaddleClas provides an example of model serving deployment based on Paddle Serving. You can refer to [Model serving deployment](../inference_deployment/paddle_serving_deploy.md) to complete the corresponding deployment. -#### 3.4 Lite deployment +#### 4.4 Lite deployment -Paddle Lite is a high-performance, lightweight, flexible and easily extensible deep learning inference framework, positioned to support mobileMultiple hardware platforms including client, embedded and server. For more introduction to Paddle Lite, please refer to the Paddle Lite code repository. +Paddle Lite is a high-performance, lightweight, flexible and easily extensible deep learning inference framework, positioned to support multiple hardware platforms including mobile, embedded and server. For more introduction to Paddle Lite, please refer to the Paddle Lite code repository. -PaddleClas provides an example of deploying models based on Paddle Lite. You can refer to [Deployment](../inference_deployment/paddle_lite_deploy_en.md) to complete the corresponding deployment. +PaddleClas provides an example of deploying models based on Paddle Lite. You can refer to [Deployment](../inference_deployment/paddle_lite_deploy.md) to complete the corresponding deployment. -#### 3.5 Paddle2ONNX model conversion and prediction +#### 4.5 Paddle2ONNX Model Conversion and Prediction -Paddle2ONNX supports converting PaddlePaddle model format to ONNX model format. The deployment of Paddle models to various inference engines can be completed through ONNX, including TensorRT/OpenVINO/MNN/TNN/NCNN, as well as other inference engines or hardware that support the ONNX open source format. For more information about Paddle2ONNX, please refer to the Paddle2ONNX code repository. +Paddle2ONNX supports converting PaddlePaddle model format to ONNX model format. The deployment of Paddle models to various inference engines can be completed through ONNX, including TensorRT/OpenVINO/MNN/TNN/NCNN, and other inference engines or hardware that support the ONNX open source format. For more information about Paddle2ONNX, please refer to the Paddle2ONNX code repository. PaddleClas provides an example of converting an inference model to an ONNX model and making inference prediction based on Paddle2ONNX. You can refer to [Paddle2ONNX model conversion and prediction](../../../deploy/paddle2onnx/readme.md) to complete the corresponding deployment work. -### 4. Summary +### 5. Summary -#### 4.1 Method summary and comparison +#### 5.1 Method summary and comparison The above algorithm can be quickly migrated to most ReID models, which can further improve the performance of ReID models. -#### 4.2 Usage advice/FAQ +#### 5.2 Usage advice/FAQ The Market1501 dataset is relatively small, so you can try to train multiple times to get the highest accuracy. -### 4. References +### 6. References 1. [Bag of Tricks and A Strong Baseline for Deep Person Re-identification](https://openaccess.thecvf.com/content_CVPRW_2019/papers/TRMTMCT/Luo_Bag_of_Tricks_and_a_Strong_Baseline_for_Deep_Person_CVPRW_2019_paper.pdf) 2. [michuanhaohao/reid-strong-baseline](https://github.com/michuanhaohao/reid-strong-baseline) 3. [Pedestrian Re-ID dataset Market1501 dataset _star_function blog-CSDN blog _market1501 dataset](https://blog.csdn.net/qq_39220334/article/details/121470106) 4. [Deep Learning for Person Re-identification: A Survey and Outlook](https://arxiv.org/abs/2001.04193) +5. [CMC and mAP in ReID Task](https://wrong.wang/blog/20190223-reid%E4%BB%BB%E5%8A%A1%E4%B8%AD%E7%9A%84cmc%E5%92%8Cmap/) diff --git a/docs/zh_CN/algorithm_introduction/reid.md b/docs/zh_CN/algorithm_introduction/reid.md index cc4b66d1a..fbf7c65f2 100644 --- a/docs/zh_CN/algorithm_introduction/reid.md +++ b/docs/zh_CN/algorithm_introduction/reid.md @@ -5,42 +5,81 @@ ## 目录 - [1. 算法/应用场景简介](#1-算法应用场景简介) -- [2. ReID算法](#2-reid算法) - - [2.1 ReID strong-baseline](#21-reid-strong-baseline) - - [2.1.1 原理介绍](#211-原理介绍) - - [2.1.2 精度指标](#212-精度指标) - - [2.1.3 数据准备](#213-数据准备) - - [2.1.4 模型训练](#214-模型训练) -- [3. 模型评估与推理部署](#3-模型评估与推理部署) - - [3.1 模型评估](#31-模型评估) - - [3.2 模型推理](#32-模型推理) - - [3.2.1 推理模型准备](#321-推理模型准备) - - [3.2.2 基于 Python 预测引擎推理](#322-基于-python-预测引擎推理) - - [3.2.3 基于 C++ 预测引擎推理](#323-基于-c-预测引擎推理) - - [3.3 服务化部署](#33-服务化部署) - - [3.4 端侧部署](#34-端侧部署) - - [3.5 Paddle2ONNX 模型转换与预测](#35-paddle2onnx-模型转换与预测) -- [4. 总结](#4-总结) - - [4.1 方法总结与对比](#41-方法总结与对比) - - [4.2 使用建议/FAQ](#42-使用建议faq) -- [4. 参考资料](#4-参考资料) +- [2. 常用数据集与指标](#2-常用数据集与指标) + - [2.1 常用数据集](#21-常用数据集) + - [2.2 常用指标](#22-常用指标) +- [3. ReID算法](#3-reid算法) + - [3.1 ReID strong-baseline](#31-reid-strong-baseline) + - [3.1.1 原理介绍](#311-原理介绍) + - [3.1.2 精度指标](#312-精度指标) + - [3.1.3 数据准备](#313-数据准备) + - [3.1.4 模型训练](#314-模型训练) +- [4. 模型评估与推理部署](#4-模型评估与推理部署) + - [4.1 模型评估](#41-模型评估) + - [4.2 模型推理](#42-模型推理) + - [4.2.1 推理模型准备](#421-推理模型准备) + - [4.2.2 基于 Python 预测引擎推理](#422-基于-python-预测引擎推理) + - [4.2.3 基于 C++ 预测引擎推理](#423-基于-c-预测引擎推理) + - [4.3 服务化部署](#43-服务化部署) + - [4.4 端侧部署](#44-端侧部署) + - [4.5 Paddle2ONNX 模型转换与预测](#45-paddle2onnx-模型转换与预测) +- [5. 总结](#5-总结) + - [5.1 方法总结与对比](#51-方法总结与对比) + - [5.2 使用建议/FAQ](#52-使用建议faq) +- [6. 参考资料](#6-参考资料) ### 1. 算法/应用场景简介 -行人重识别(Person re-identification)也称行人再识别,是利用计算机视觉技术判断图像或者视频序列中是否存在特定行人的技术。广泛被认为是一个图像检索的子问题。给定一个监控行人图像,检索跨设备下的该行人图像。旨在弥补固定的摄像头的视觉局限,并可与行人检测/行人跟踪技术相结合,可广泛应用于智能视频监控、智能安保等领域。 +行人重识别(Person re-identification, Re-ID)也称行人再识别,作为跨镜头的行人检索问题被广泛研究。给定某一个摄像机拍摄下的行人图片,目标是判断该行人是否在不同相机或者不同时间段拍摄的画面中出现过。给定的行人数据可以是一张图片,也可以是视频帧,甚至可以是一段文字描述。近年来,公共安全领域对该技术的应用需求日益增加,行人重识别在智能监控技术中的影响也越来越大。 + +目前行人重识别仍然是一个具有挑战性的任务,尤其是不同的视点、分辨率、光照变化、遮挡情况、多模态,以及复杂的相机环境与背景、标注数据噪声等问题,给识别算法带来了很大的不确定性。另外,在实际落地时,拍摄相机可能会发生变化,大规模的检索库、数据集的分布偏移、未知的场景、模型增量更新以及检索人物的服装变化,这同样增加了不少困难。 + +早期的行人重识别工作主要关注手工设计特征提取算子,包括加入人体姿态特征,或者距离度量函数的学习。随着深度学习技术的发展,行人重识也取得了巨大的进步。总的来说,行人重识别整个过程包括5个步骤:1)数据采集,2)行人位置框标注,3)行人类别标注,4)模型训练,5)行人检索(模型测试)。 -常见的行人重识别方法通过特征提取模块来提取输入图片的局部/全局、单粒度/多粒度特征,再经过融合模块得到一个高维的特征向量。在训练时使用分类头将该特征向量转换成属于每个类别的概率从而以分类任务的方式来优化特征提取模型;在测试或推理时直接将高维的特征向量作为图片描述向量在检索向量库中进行检索,以得到检索结果。而ReID strong-baseline算法则是提出了多个有效优化训练与检索的方法来提升整体模型性能。 -### 2. ReID算法 +### 2. 常用数据集与指标 -#### 2.1 ReID strong-baseline +#### 2.1 常用数据集 + +| Dataset | #ID | #Image | #cam | +| :---------- | :----: | :----: | :---: | +| VIPeR | 632 | 1264 | 2 | +| iLIDS | 119 | 476 | 2 | +| GRID | 250 | 1275 | 2 | +| PRID2011 | 200 | 1134 | 2 | +| CUHK01 | 971 | 3884 | 2 | +| CUHK02 | 1816 | 7264 | 2 | +| CUHK03 | 1467 | 13164 | 2 | +| Market-1501 | 1501 | 32668 | 2 | +| DukeMTMC | 1404 | 36411 | 2 | +| Airport | 39902 | 39902 | 2 | +| MSMT17 | 126441 | 126441 | 2 | + +#### 2.2 常用指标 + +1. CMC曲线 + + 公式如下: + $$ CMC(K)=\frac{1}{N} \sum_{i=1}^{N} \begin{cases} 1, & \text{if $label_i \in Top{K}(result_i)$} \\\\ 0, & \text{if $label_i \notin Top{K}(result_i)$} \end{cases} $$ + + 其中$N$为查询样本的数量,$result_i$为每个查询样本检索结果的标签集合,根据公式可以将CMC曲线理解为Top1-Acc、Top2-Acc、...、TopK-Acc构成的数组,显然这是一个单调不降的曲线。其中常见的Rank-1、Top1-Acc指标即是指CMC(1) + +2. mAP指标 + + 假设使用一个查询样本,返回了一组查询结果,那么按照以下公式,逐个考虑前K个查询结果,对于每个K,算出其精确率Precision和召回率Recall。 + $$\begin{align} precision&=\frac{|\\{同类别图片\\} \cap \\{前K个查询结果\\}|}{|\\{前K个查询结果\\}|} \\\\ recall&=\frac{|\\{同类别图片\\} \cap \\{前K个查询结果\\}|}{|\\{同类别图片\\}|} \end{align}$$ + 将得到的多组(Precision, Recall)化成曲线图,该曲线与坐标轴围成的面积,称为Average Precision(AP), + 对于每个样本,计算其AP值,然后取平均,就得到了mAP指标。 +### 3. ReID算法 + +#### 3.1 ReID strong-baseline 论文出处:[Bag of Tricks and A Strong Baseline for Deep Person Re-identification](https://openaccess.thecvf.com/content_CVPRW_2019/papers/TRMTMCT/Luo_Bag_of_Tricks_and_a_Strong_Baseline_for_Deep_Person_CVPRW_2019_paper.pdf) -##### 2.1.1 原理介绍 +##### 3.1.1 原理介绍 作者以普遍使用的基于 ResNet50 的行人重识别模型为基础,探索并总结了以下几种有效且适用性较强的优化方法,大幅度提高了在多个行人重识别数据集上的指标。 @@ -52,12 +91,12 @@ 6. Center loss:给每个类别一个可学习的聚类中心,训练时让类内特征靠近聚类中心,减少类内差异,增大类间差异。 7. Reranking:在检索时考虑查询图像的近邻候选对象,根据候选对象的近邻图像的是否也含有查询图像的情况来优化距离矩阵,最终提升检索精度。 -##### 2.1.2 精度指标 +##### 3.1.2 精度指标 以下表格总结了复现的ReID strong-baseline的3种配置在 Market1501 数据集上的精度指标, -| 配置文件 | recall@1(\%) | mAP(\%) | 参考recall@1(\%) | 参考mAP(\%) | 预训练模型下载地址 | inference模型下载地址 | -| -------------------------------- | ------------ | ------- | ---------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | +| 配置文件 | recall@1(\%) | mAP(\%) | 参考recall@1(\%) | 参考mAP(\%) | 预训练模型下载地址 | inference模型下载地址 | +| -------------------------------- | ------------ | ------- | ---------------- | ----------- | ----- | ---- | | baseline.yaml | 88.45 | 74.37 | 87.7 | 74.0 | [下载链接](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/baseline_pretrained.pdparams) | [下载链接](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/baseline_infer.tar) | | softmax_triplet.yaml | 94.29 | 85.57 | 94.1 | 85.7 | [下载链接](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/softmax_triplet_pretrained.pdparams) | [下载链接](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/softmax_triplet_infer.tar) | | softmax_triplet_with_center.yaml | 94.50 | 85.82 | 94.5 | 85.9 | [下载链接](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/softmax_triplet_with_center_pretrained.pdparams) | [下载链接](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/softmax_triplet_with_center_infer.tar) | @@ -66,7 +105,7 @@ 接下来主要以`softmax_triplet_with_center.yaml`配置和训练好的模型文件为例,展示在 Market1501 数据集上进行训练、测试、推理的过程。 -##### 2.1.3 数据准备 +##### 3.1.3 数据准备 下载 [Market-1501-v15.09.15.zip](https://pan.baidu.com/s/1ntIi2Op?_at_=1654142245770) 数据集,解压到`PaddleClas/dataset/`下,并组织成以下文件结构: @@ -85,7 +124,7 @@ └── readme.txt ``` -##### 2.1.4 模型训练 +##### 3.1.4 模型训练 1. 执行以下命令开始训练 @@ -118,9 +157,9 @@ 训练过程中会在屏幕上实时打印loss等指标信息,同时会保存日志文件`train.log`、模型参数文件`*.pdparams`、优化器参数文件`*.pdopt`等内容到`Global.output_dir`指定的文件夹下,默认在`PaddleClas/output/RecModel/`文件夹下。 -### 3. 模型评估与推理部署 +### 4. 模型评估与推理部署 -#### 3.1 模型评估 +#### 4.1 模型评估 准备用于评估的`*.pdparams`模型参数文件,可以使用训练好的模型,也可以使用[2.1.4 模型训练](#214-模型训练)中保存的模型。 @@ -170,9 +209,9 @@ ``` 默认评估日志保存在`PaddleClas/output/RecModel/eval.log`中,可以看到我们提供的 `softmax_triplet_with_center_pretrained.pdparams` 模型在 Market1501 数据集上的评估指标为recall@1=0.94507,recall@5=0.98248,mAP=0.85827 -#### 3.2 模型推理 +#### 4.2 模型推理 -##### 3.2.1 推理模型准备 +##### 4.2.1 推理模型准备 可以将训练过程中保存的模型文件转换成 inference 模型并推理,或者使用我们提供的转换好的 inference 模型直接进行推理 - 将训练过程中保存的模型文件转换成 inference 模型,同样以 `latest.pdparams` 为例,执行以下命令进行转换 @@ -191,7 +230,7 @@ cd ../ ``` -##### 3.2.2 基于 Python 预测引擎推理 +##### 4.2.2 基于 Python 预测引擎推理 1. 修改 `PaddleClas/deploy/configs/inference_rec.yaml` - 将 `infer_imgs:` 后的路径段改为 Market1501 中 query 文件夹下的任意一张图片路径(下方配置使用的是`0294_c1s1_066631_00.jpg`图片的路径) @@ -245,41 +284,42 @@ 4. 批量预测,将配置文件中`infer_imgs:`后的路径改为为文件夹即可,如`../dataset/market1501/Market-1501-v15.09.15/query`,会预测并逐个输出query下所有图片的特征向量。 -##### 3.2.3 基于 C++ 预测引擎推理 +##### 4.2.3 基于 C++ 预测引擎推理 PaddleClas 提供了基于 C++ 预测引擎推理的示例,您可以参考[服务器端 C++ 预测](../inference_deployment/cpp_deploy.md)来完成相应的推理部署。如果您使用的是 Windows 平台,可以参考基于 Visual Studio 2019 Community CMake 编译指南完成相应的预测库编译和模型预测工作。 -#### 3.3 服务化部署 +#### 4.3 服务化部署 Paddle Serving 提供高性能、灵活易用的工业级在线推理服务。Paddle Serving 支持 RESTful、gRPC、bRPC 等多种协议,提供多种异构硬件和多种操作系统环境下推理解决方案。更多关于Paddle Serving 的介绍,可以参考Paddle Serving 代码仓库。 PaddleClas 提供了基于 Paddle Serving 来完成模型服务化部署的示例,您可以参考[模型服务化部署](../inference_deployment/paddle_serving_deploy.md)来完成相应的部署工作。 -#### 3.4 端侧部署 +#### 4.4 端侧部署 Paddle Lite 是一个高性能、轻量级、灵活性强且易于扩展的深度学习推理框架,定位于支持包括移动端、嵌入式以及服务器端在内的多硬件平台。更多关于 Paddle Lite 的介绍,可以参考Paddle Lite 代码仓库。 PaddleClas 提供了基于 Paddle Lite 来完成模型端侧部署的示例,您可以参考[端侧部署](../inference_deployment/paddle_lite_deploy.md)来完成相应的部署工作。 -#### 3.5 Paddle2ONNX 模型转换与预测 +#### 4.5 Paddle2ONNX 模型转换与预测 Paddle2ONNX 支持将 PaddlePaddle 模型格式转化到 ONNX 模型格式。通过 ONNX 可以完成将 Paddle 模型到多种推理引擎的部署,包括TensorRT/OpenVINO/MNN/TNN/NCNN,以及其它对 ONNX 开源格式进行支持的推理引擎或硬件。更多关于 Paddle2ONNX 的介绍,可以参考Paddle2ONNX 代码仓库。 PaddleClas 提供了基于 Paddle2ONNX 来完成 inference 模型转换 ONNX 模型并作推理预测的示例,您可以参考[Paddle2ONNX 模型转换与预测](../../../deploy/paddle2onnx/readme.md)来完成相应的部署工作。 -### 4. 总结 +### 5. 总结 -#### 4.1 方法总结与对比 +#### 5.1 方法总结与对比 上述算法能快速地迁移至多数的ReID模型中,能进一步提升ReID模型的性能。 -#### 4.2 使用建议/FAQ +#### 5.2 使用建议/FAQ Market1501 数据集比较小,可以尝试训练多次取最高精度。 -### 4. 参考资料 +### 6. 参考资料 1. [Bag of Tricks and A Strong Baseline for Deep Person Re-identification](https://openaccess.thecvf.com/content_CVPRW_2019/papers/TRMTMCT/Luo_Bag_of_Tricks_and_a_Strong_Baseline_for_Deep_Person_CVPRW_2019_paper.pdf) 2. [michuanhaohao/reid-strong-baseline](https://github.com/michuanhaohao/reid-strong-baseline) 3. [行人重识别数据集之 Market1501 数据集_star_function的博客-CSDN博客_market1501数据集](https://blog.csdn.net/qq_39220334/article/details/121470106) 4. [Deep Learning for Person Re-identification:A Survey and Outlook](https://arxiv.org/abs/2001.04193) +5. [ReID任务中的CMC和mAP](https://wrong.wang/blog/20190223-reid%E4%BB%BB%E5%8A%A1%E4%B8%AD%E7%9A%84cmc%E5%92%8Cmap/) From bcc6aa3a48c2137e52e14ed178c2af03b265bd0d Mon Sep 17 00:00:00 2001 From: HydrogenSulfate <490868991@qq.com> Date: Mon, 4 Jul 2022 13:30:21 +0800 Subject: [PATCH 9/9] add re-ranking option and related description --- docs/en/algorithm_introduction/reid.md | 51 ++++++++++++++++++--- docs/zh_CN/algorithm_introduction/reid.md | 54 +++++++++++++++++++---- 2 files changed, 91 insertions(+), 14 deletions(-) diff --git a/docs/en/algorithm_introduction/reid.md b/docs/en/algorithm_introduction/reid.md index b69e9d0cc..c4c5ac59e 100644 --- a/docs/en/algorithm_introduction/reid.md +++ b/docs/en/algorithm_introduction/reid.md @@ -46,15 +46,15 @@ Early work on person re-identification mainly focused on hand-designed feature e | :---------- | :----: | :----: | :---: | | VIPeR | 632 | 1264 | 2 | | iLIDS | 119 | 476 | 2 | -| GRID | 250 | 1275 | 2 | +| GRID | 250 | 1275 | 8 | | PRID2011 | 200 | 1134 | 2 | | CUHK01 | 971 | 3884 | 2 | -| CUHK02 | 1816 | 7264 | 2 | +| CUHK02 | 1816 | 7264 | 10 | | CUHK03 | 1467 | 13164 | 2 | -| Market-1501 | 1501 | 32668 | 2 | -| DukeMTMC | 1404 | 36411 | 2 | -| Airport | 39902 | 39902 | 2 | -| MSMT17 | 126441 | 126441 | 2 | +| Market-1501 | 1501 | 32668 | 6 | +| DukeMTMC | 1404 | 36411 | 8 | +| Airport | 39902 | 39902 | 6 | +| MSMT17 | 126441 | 126441 | 15 | #### 2.2 Common metric @@ -209,6 +209,45 @@ Prepare the `*.pdparams` model parameter file for evaluation. You can use the tr ``` The default evaluation log is saved in `PaddleClas/output/RecModel/eval.log`. You can see that the evaluation indicators of the `softmax_triplet_with_center_pretrained.pdparams` model provided by us on the Market1501 dataset are recall@1=0.94507, recall@5=0.98248 , mAP=0.85827 +- use the re-ranking option to improve the evaluation metrics + + The main idea of ​​re-ranking is to use the relationship between the retrieval libraries to further optimize the retrieval results, and the k-reciprocal algorithm is widely used. Turn on re-ranking during evaluation in PaddleClas to improve the final retrieval accuracy. + This can be enabled by adding `-o Global.re_ranking=True` to the evaluation command as shown below. + ```bash + python3.7 tools/eval.py \ + -c ppcls/configs/reid/strong_baseline/softmax_triplet_with_center.yaml \ + -o Global.pretrained_model="pretrained_models/softmax_triplet_with_center_pretrained" \ + -o Global.re_ranking=True + ``` + + View the output + ```log + ... + ... + ppcls INFO: unique_endpoints {''} + ppcls INFO: Found /root/.paddleclas/weights/resnet50-19c8e357_torch2paddle.pdparams + ppcls INFO: gallery feature calculation process: [0/125] + ppcls INFO: gallery feature calculation process: [20/125] + ppcls INFO: gallery feature calculation process: [40/125] + ppcls INFO: gallery feature calculation process: [60/125] + ppcls INFO: gallery feature calculation process: [80/125] + ppcls INFO: gallery feature calculation process: [100/125] + ppcls INFO: gallery feature calculation process: [120/125] + ppcls INFO: Build gallery done, all feat shape: [15913, 2048], begin to eval.. + ppcls INFO: query feature calculation process: [0/27] + ppcls INFO: query feature calculation process: [20/27] + ppcls INFO: Build query done, all feat shape: [3368, 2048], begin to eval.. + ppcls INFO: re_ranking=True + ppcls WARNING: re_ranking=True, Recallk.descending has been set to False + ppcls WARNING: re_ranking=True,mAP.descending has been set to False + ppcls INFO: using GPU to compute original distance + ppcls INFO: starting re_ranking + ppcls INFO: [Eval][Epoch 0][Avg]recall1: 0.95546, recall5: 0.97743, mAP: 0.94252 + ``` + It can be seen that after re-ranking is enabled, the evaluation indicators are recall@1=0.95546, recall@5=0.97743, and mAP=0.94252. It can be found that the algorithm improves the mAP indicator significantly (0.85827->0.94252). + + **Note**: The computational complexity of re-ranking is currently high, so it is not enabled by default. + #### 4.2 Model Inference ##### 4.2.1 Inference model preparation diff --git a/docs/zh_CN/algorithm_introduction/reid.md b/docs/zh_CN/algorithm_introduction/reid.md index fbf7c65f2..4c0cad846 100644 --- a/docs/zh_CN/algorithm_introduction/reid.md +++ b/docs/zh_CN/algorithm_introduction/reid.md @@ -46,15 +46,15 @@ | :---------- | :----: | :----: | :---: | | VIPeR | 632 | 1264 | 2 | | iLIDS | 119 | 476 | 2 | -| GRID | 250 | 1275 | 2 | +| GRID | 250 | 1275 | 8 | | PRID2011 | 200 | 1134 | 2 | | CUHK01 | 971 | 3884 | 2 | -| CUHK02 | 1816 | 7264 | 2 | +| CUHK02 | 1816 | 7264 | 10 | | CUHK03 | 1467 | 13164 | 2 | -| Market-1501 | 1501 | 32668 | 2 | -| DukeMTMC | 1404 | 36411 | 2 | -| Airport | 39902 | 39902 | 2 | -| MSMT17 | 126441 | 126441 | 2 | +| Market-1501 | 1501 | 32668 | 6 | +| DukeMTMC | 1404 | 36411 | 8 | +| Airport | 39902 | 39902 | 6 | +| MSMT17 | 126441 | 126441 | 15 | #### 2.2 常用指标 @@ -95,8 +95,8 @@ 以下表格总结了复现的ReID strong-baseline的3种配置在 Market1501 数据集上的精度指标, -| 配置文件 | recall@1(\%) | mAP(\%) | 参考recall@1(\%) | 参考mAP(\%) | 预训练模型下载地址 | inference模型下载地址 | -| -------------------------------- | ------------ | ------- | ---------------- | ----------- | ----- | ---- | +| 配置文件 | recall@1(\%) | mAP(\%) | 参考recall@1(\%) | 参考mAP(\%) | 预训练模型下载地址 | inference模型下载地址 | +| -------------------------------- | ------------ | ------- | ---------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | | baseline.yaml | 88.45 | 74.37 | 87.7 | 74.0 | [下载链接](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/baseline_pretrained.pdparams) | [下载链接](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/baseline_infer.tar) | | softmax_triplet.yaml | 94.29 | 85.57 | 94.1 | 85.7 | [下载链接](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/softmax_triplet_pretrained.pdparams) | [下载链接](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/softmax_triplet_infer.tar) | | softmax_triplet_with_center.yaml | 94.50 | 85.82 | 94.5 | 85.9 | [下载链接](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/pretrain/softmax_triplet_with_center_pretrained.pdparams) | [下载链接](https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/rec/reid/inference/softmax_triplet_with_center_infer.tar) | @@ -209,6 +209,44 @@ ``` 默认评估日志保存在`PaddleClas/output/RecModel/eval.log`中,可以看到我们提供的 `softmax_triplet_with_center_pretrained.pdparams` 模型在 Market1501 数据集上的评估指标为recall@1=0.94507,recall@5=0.98248,mAP=0.85827 +- 使用re-ranking功能提升评估精度 + + re-ranking的主要思想是利用检索库之间的相互关系来进一步优化检索结果,比较广泛使用的是k-reciprocal算法。在PaddleClas中在评估时开启re-ranking来提升最终的检索精度。 + 如下所示,在评估命令中加上 `-o Global.re_ranking=True` 即可开启该功能。 + ```bash + python3.7 tools/eval.py \ + -c ppcls/configs/reid/strong_baseline/softmax_triplet_with_center.yaml \ + -o Global.pretrained_model="pretrained_models/softmax_triplet_with_center_pretrained" \ + -o Global.re_ranking=True + ``` + 查看输出结果 + ```log + ... + ... + ppcls INFO: unique_endpoints {''} + ppcls INFO: Found /root/.paddleclas/weights/resnet50-19c8e357_torch2paddle.pdparams + ppcls INFO: gallery feature calculation process: [0/125] + ppcls INFO: gallery feature calculation process: [20/125] + ppcls INFO: gallery feature calculation process: [40/125] + ppcls INFO: gallery feature calculation process: [60/125] + ppcls INFO: gallery feature calculation process: [80/125] + ppcls INFO: gallery feature calculation process: [100/125] + ppcls INFO: gallery feature calculation process: [120/125] + ppcls INFO: Build gallery done, all feat shape: [15913, 2048], begin to eval.. + ppcls INFO: query feature calculation process: [0/27] + ppcls INFO: query feature calculation process: [20/27] + ppcls INFO: Build query done, all feat shape: [3368, 2048], begin to eval.. + ppcls INFO: re_ranking=True + ppcls WARNING: re_ranking=True,Recallk.descending has been set to False + ppcls WARNING: re_ranking=True,mAP.descending has been set to False + ppcls INFO: using GPU to compute original distance + ppcls INFO: starting re_ranking + ppcls INFO: [Eval][Epoch 0][Avg]recall1: 0.95546, recall5: 0.97743, mAP: 0.94252 + ``` + 可以看到开启re-ranking后,评估指标为recall@1=0.95546,recall@5=0.97743,mAP=0.94252,可以发现该算法对mAP指标的提升比较明显(0.85827->0.94252)。 + + **注**:目前re-ranking的计算复杂度较高,因此默认不启用。 + #### 4.2 模型推理 ##### 4.2.1 推理模型准备