From 129ddbb219d22ef697bf2d3d16a5eb0277e40359 Mon Sep 17 00:00:00 2001 From: Kehan Yin <838278270@qq.com> Date: Thu, 1 Jun 2023 14:15:48 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90Hackathon=20+=20No.161=E3=80=91?= =?UTF-8?q?=E8=AE=BA=E6=96=87=E5=A4=8D=E7=8E=B0=EF=BC=9ACLRNet:=20Cross=20?= =?UTF-8?q?Layer=20Refinement=20Network=20for=20Lane=20Detection=20(#8278)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Feat add CLRNet * Update CLRNet README.md * Update requirements: add imgaug>=0.4.0 for CLRNet * Update CLRNet README.md * Update README.md * Update Rename clrnet_utils.py * Update CLRNet demo & delete demo result * Update README.md add weight for culane * Update README.cn.md add training logs * Feat add dataset download * Fix bugs when lanes is empty * Update README * Update README for dataset info * Fix export model * Update configs & README * style: update codestyle * Style update op codestyple * Fix eval process * Fix eval process * Update README&configs * Fix deploy infer * Fix mkdir in lane visualize * Docs Update README * Docs Rename configs * Docs update weights --------- Co-authored-by: LokeZhou --- configs/clrnet/README.cn.md | 68 ++ configs/clrnet/README.md | 68 ++ configs/clrnet/_base_/clrnet_r18_fpn.yml | 41 ++ configs/clrnet/_base_/clrnet_reader.yml | 37 + configs/clrnet/_base_/optimizer_1x.yml | 14 + configs/clrnet/clrnet_resnet18_culane.yml | 9 + configs/datasets/culane.yml | 28 + demo/lane00000.jpg | Bin 0 -> 263368 bytes deploy/python/clrnet_postprocess.py | 180 +++++ deploy/python/infer.py | 125 +++- deploy/python/preprocess.py | 27 + deploy/python/visualize.py | 60 ++ ppdet/data/culane_utils.py | 130 ++++ ppdet/data/source/__init__.py | 2 + ppdet/data/source/culane.py | 206 ++++++ ppdet/data/transform/__init__.py | 3 + ppdet/data/transform/culane_operators.py | 366 +++++++++ ppdet/engine/export_utils.py | 32 +- ppdet/engine/trainer.py | 122 ++- ppdet/metrics/__init__.py | 6 +- ppdet/metrics/culane_metrics.py | 327 ++++++++ ppdet/modeling/architectures/__init__.py | 4 +- ppdet/modeling/architectures/clrnet.py | 67 ++ ppdet/modeling/assigners/clrnet_assigner.py | 147 ++++ ppdet/modeling/backbones/__init__.py | 2 + ppdet/modeling/backbones/clrnet_resnet.py | 697 ++++++++++++++++++ ppdet/modeling/clrnet_utils.py | 309 ++++++++ ppdet/modeling/heads/__init__.py | 4 +- ppdet/modeling/heads/clrnet_head.py | 399 ++++++++++ ppdet/modeling/lane_utils.py | 111 +++ ppdet/modeling/losses/__init__.py | 4 + ppdet/modeling/losses/clrnet_line_iou_loss.py | 41 ++ ppdet/modeling/losses/clrnet_loss.py | 283 +++++++ ppdet/modeling/necks/__init__.py | 2 + ppdet/modeling/necks/clrnet_fpn.py | 254 +++++++ ppdet/utils/download.py | 3 +- requirements.txt | 3 + tools/infer_culane.py | 165 +++++ 38 files changed, 4334 insertions(+), 12 deletions(-) create mode 100644 configs/clrnet/README.cn.md create mode 100644 configs/clrnet/README.md create mode 100644 configs/clrnet/_base_/clrnet_r18_fpn.yml create mode 100644 configs/clrnet/_base_/clrnet_reader.yml create mode 100644 configs/clrnet/_base_/optimizer_1x.yml create mode 100644 configs/clrnet/clrnet_resnet18_culane.yml create mode 100644 configs/datasets/culane.yml create mode 100644 demo/lane00000.jpg create mode 100644 deploy/python/clrnet_postprocess.py create mode 100644 ppdet/data/culane_utils.py create mode 100644 ppdet/data/source/culane.py create mode 100644 ppdet/data/transform/culane_operators.py create mode 100644 ppdet/metrics/culane_metrics.py create mode 100644 ppdet/modeling/architectures/clrnet.py create mode 100644 ppdet/modeling/assigners/clrnet_assigner.py create mode 100644 ppdet/modeling/backbones/clrnet_resnet.py create mode 100644 ppdet/modeling/clrnet_utils.py create mode 100644 ppdet/modeling/heads/clrnet_head.py create mode 100644 ppdet/modeling/lane_utils.py create mode 100644 ppdet/modeling/losses/clrnet_line_iou_loss.py create mode 100644 ppdet/modeling/losses/clrnet_loss.py create mode 100644 ppdet/modeling/necks/clrnet_fpn.py create mode 100644 tools/infer_culane.py diff --git a/configs/clrnet/README.cn.md b/configs/clrnet/README.cn.md new file mode 100644 index 000000000..422709e43 --- /dev/null +++ b/configs/clrnet/README.cn.md @@ -0,0 +1,68 @@ +简体中文 | [English](README.md) + +# CLRNet (CLRNet: Cross Layer Refinement Network for Lane Detection) + +## 目录 +- [简介](#简介) +- [模型库](#模型库) +- [引用](#引用) + +## 介绍 + +[CLRNet](https://arxiv.org/abs/2203.10350)是一个车道线检测模型。CLRNet模型设计了车道线检测的直线先验轨迹,车道线iou以及nms方法,融合提取车道线轨迹的上下文高层特征与底层特征,利用FPN多尺度进行refine,在车道线检测相关数据集取得了SOTA的性能。 + +## 模型库 + +### CLRNet在CUlane上结果 + +| 骨架网络 | mF1 | F1@50 | F1@75 | 下载链接 | 配置文件 |训练日志| +| :--------------| :------- | :----: | :------: | :----: |:-----: |:-----: | +| ResNet-18 | 54.98 | 79.46 | 62.10 | [下载链接](https://paddledet.bj.bcebos.com/models/clrnet_resnet18_culane.pdparams) | [配置文件](./clrnet_resnet18_culane.yml) |[训练日志](https://bj.bcebos.com/v1/paddledet/logs/train_clrnet_r18_15_culane.log)| + +### 数据集下载 +下载[CULane数据集](https://xingangpan.github.io/projects/CULane.html)并解压到`dataset/culane`目录。 + +您的数据集目录结构如下: +```shell +culane/driver_xx_xxframe # data folders x6 +culane/laneseg_label_w16 # lane segmentation labels +culane/list # data lists +``` +如果您使用百度云链接下载,注意确保`driver_23_30frame_part1.tar.gz`和`driver_23_30frame_part2.tar.gz`解压后的文件都在`driver_23_30frame`目录下。 + +现已将用于测试的小数据集上传到PaddleDetection,可通过运行训练脚本,自动下载并解压数据,如需复现结果请下载链接中的全量数据集训练。 + +### 训练 +- GPU单卡训练 +```shell +python tools/train.py -c configs/clrnet/clr_resnet18_culane.yml +``` +- GPU多卡训练 +```shell +export CUDA_VISIBLE_DEVICES=0,1,2,3 +python -m paddle.distributed.launch --gpus 0,1,2,3 tools/train.py -c configs/clrnet/clr_resnet18_culane.yml +``` + +### 评估 +```shell +python tools/eval.py -c configs/clrnet/clr_resnet18_culane.yml -o weights=output/clr_resnet18_culane/model_final.pdparams +``` + +### 预测 +```shell +python tools/infer_culane.py -c configs/clrnet/clr_resnet18_culane.yml -o weights=output/clr_resnet18_culane/model_final.pdparams --infer_img=demo/lane00000.jpg +``` + +注意:预测功能暂不支持模型静态图推理部署。 + +## 引用 +``` +@InProceedings{Zheng_2022_CVPR, + author = {Zheng, Tu and Huang, Yifei and Liu, Yang and Tang, Wenjian and Yang, Zheng and Cai, Deng and He, Xiaofei}, + title = {CLRNet: Cross Layer Refinement Network for Lane Detection}, + booktitle = {Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition (CVPR)}, + month = {June}, + year = {2022}, + pages = {898-907} +} +``` diff --git a/configs/clrnet/README.md b/configs/clrnet/README.md new file mode 100644 index 000000000..f61b0c86c --- /dev/null +++ b/configs/clrnet/README.md @@ -0,0 +1,68 @@ +English | [简体中文](README_cn.md) + +# CLRNet (CLRNet: Cross Layer Refinement Network for Lane Detection) + +## Table of Contents +- [Introduction](#Introduction) +- [Model Zoo](#Model_Zoo) +- [Citations](#Citations) + +## Introduction + +[CLRNet](https://arxiv.org/abs/2203.10350) is a lane detection model. The CLRNet model is designed with line prior for lane detection, line iou loss as well as nms method, fused to extract contextual high-level features of lane line with low-level features, and refined by FPN multi-scale. Finally, the model achieved SOTA performance in lane detection datasets. + +## Model Zoo + +### CLRNet Results on CULane dataset + +| backbone | mF1 | F1@50 | F1@75 | download | config | +| :--------------| :------- | :----: | :------: | :----: |:-----: | +| ResNet-18 | 54.98 | 79.46 | 62.10 | [model](https://paddledet.bj.bcebos.com/models/clrnet_resnet18_culane.pdparams) | [config](./clrnet_resnet18_culane.yml) | + +### Download +Download [CULane](https://xingangpan.github.io/projects/CULane.html). Then extract them to `dataset/culane`. + +For CULane, you should have structure like this: +```shell +culane/driver_xx_xxframe # data folders x6 +culane/laneseg_label_w16 # lane segmentation labels +culane/list # data lists +``` +If you use Baidu Cloud, make sure that images in `driver_23_30frame_part1.tar.gz` and `driver_23_30frame_part2.tar.gz` are located in one folder `driver_23_30frame` instead of two seperate folders after you decompress them. + +Now we have uploaded a small subset of CULane dataset to PaddleDetection for code checking. You can simply run the training script below to download it automatically. If you want to implement the results, you need to download the full dataset at th link for training. + +### Training +- single GPU +```shell +python tools/train.py -c configs/clrnet/clr_resnet18_culane.yml +``` +- multi GPU +```shell +export CUDA_VISIBLE_DEVICES=0,1,2,3 +python -m paddle.distributed.launch --gpus 0,1,2,3 tools/train.py -c configs/clrnet/clr_resnet18_culane.yml +``` + +### Evaluation +```shell +python tools/eval.py -c configs/clrnet/clr_resnet18_culane.yml -o weights=output/clr_resnet18_culane/model_final.pdparams +``` + +### Inference +```shell +python tools/infer_culane.py -c configs/clrnet/clr_resnet18_culane.yml -o weights=output/clr_resnet18_culane/model_final.pdparams --infer_img=demo/lane00000.jpg +``` + +Notice: The inference phase does not support static model graph deploy at present. + +## Citations +``` +@InProceedings{Zheng_2022_CVPR, + author = {Zheng, Tu and Huang, Yifei and Liu, Yang and Tang, Wenjian and Yang, Zheng and Cai, Deng and He, Xiaofei}, + title = {CLRNet: Cross Layer Refinement Network for Lane Detection}, + booktitle = {Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition (CVPR)}, + month = {June}, + year = {2022}, + pages = {898-907} +} +``` diff --git a/configs/clrnet/_base_/clrnet_r18_fpn.yml b/configs/clrnet/_base_/clrnet_r18_fpn.yml new file mode 100644 index 000000000..5b109814c --- /dev/null +++ b/configs/clrnet/_base_/clrnet_r18_fpn.yml @@ -0,0 +1,41 @@ +architecture: CLRNet + +CLRNet: + backbone: CLRResNet + neck: CLRFPN + clr_head: CLRHead + +CLRResNet: + resnet: 'resnet18' + pretrained: True + +CLRFPN: + in_channels: [128,256,512] + out_channel: 64 + extra_stage: 0 + +CLRHead: + prior_feat_channels: 64 + fc_hidden_dim: 64 + num_priors: 192 + num_fc: 2 + refine_layers: 3 + sample_points: 36 + loss: CLRNetLoss + conf_threshold: 0.4 + nms_thres: 0.8 + +CLRNetLoss: + cls_loss_weight : 2.0 + xyt_loss_weight : 0.2 + iou_loss_weight : 2.0 + seg_loss_weight : 1.0 + refine_layers : 3 + ignore_label: 255 + bg_weight: 0.4 + +# for visualize lane detection results +sample_y: + start: 589 + end: 230 + step: -20 diff --git a/configs/clrnet/_base_/clrnet_reader.yml b/configs/clrnet/_base_/clrnet_reader.yml new file mode 100644 index 000000000..b5eb77dae --- /dev/null +++ b/configs/clrnet/_base_/clrnet_reader.yml @@ -0,0 +1,37 @@ +worker_num: 10 + +img_h: &img_h 320 +img_w: &img_w 800 +ori_img_h: &ori_img_h 590 +ori_img_w: &ori_img_w 1640 +num_points: &num_points 72 +max_lanes: &max_lanes 4 + +TrainReader: + batch_size: 24 + batch_transforms: + - CULaneTrainProcess: {img_h: *img_h, img_w: *img_w} + - CULaneDataProcess: {num_points: *num_points, max_lanes: *max_lanes, img_w: *img_w, img_h: *img_h} + shuffle: True + drop_last: False + + + + +EvalReader: + batch_size: 24 + batch_transforms: + - CULaneResize: {prob: 1.0, img_h: *img_h, img_w: *img_w} + - CULaneDataProcess: {num_points: *num_points, max_lanes: *max_lanes, img_w: *img_w, img_h: *img_h} + shuffle: False + drop_last: False + + + +TestReader: + batch_size: 24 + batch_transforms: + - CULaneResize: {prob: 1.0, img_h: *img_h, img_w: *img_w} + - CULaneDataProcess: {num_points: *num_points, max_lanes: *max_lanes, img_w: *img_w, img_h: *img_h} + shuffle: False + drop_last: False diff --git a/configs/clrnet/_base_/optimizer_1x.yml b/configs/clrnet/_base_/optimizer_1x.yml new file mode 100644 index 000000000..f35407e1e --- /dev/null +++ b/configs/clrnet/_base_/optimizer_1x.yml @@ -0,0 +1,14 @@ +epoch: 15 +snapshot_epoch: 5 + +LearningRate: + base_lr: 0.6e-3 + schedulers: + - !CosineDecay + max_epochs: 15 + use_warmup: False + +OptimizerBuilder: + regularizer: False + optimizer: + type: AdamW diff --git a/configs/clrnet/clrnet_resnet18_culane.yml b/configs/clrnet/clrnet_resnet18_culane.yml new file mode 100644 index 000000000..f7e7acd34 --- /dev/null +++ b/configs/clrnet/clrnet_resnet18_culane.yml @@ -0,0 +1,9 @@ +_BASE_: [ + '../datasets/culane.yml', + '_base_/clrnet_reader.yml', + '_base_/clrnet_r18_fpn.yml', + '_base_/optimizer_1x.yml', + '../runtime.yml' +] + +weights: output/clr_resnet18_culane/model_final diff --git a/configs/datasets/culane.yml b/configs/datasets/culane.yml new file mode 100644 index 000000000..79e59e3eb --- /dev/null +++ b/configs/datasets/culane.yml @@ -0,0 +1,28 @@ +metric: CULaneMetric +num_classes: 5 # 4 lanes + background + +cut_height: &cut_height 270 +dataset_dir: &dataset_dir dataset/culane + +TrainDataset: + name: CULaneDataSet + dataset_dir: *dataset_dir + list_path: 'list/train_gt.txt' + split: train + cut_height: *cut_height + + +EvalDataset: + name: CULaneDataSet + dataset_dir: *dataset_dir + list_path: 'list/test.txt' + split: test + cut_height: *cut_height + + +TestDataset: + name: CULaneDataSet + dataset_dir: *dataset_dir + list_path: 'list/test.txt' + split: test + cut_height: *cut_height diff --git a/demo/lane00000.jpg b/demo/lane00000.jpg new file mode 100644 index 0000000000000000000000000000000000000000..01f3d1db1fee6eeb8ceb9ee084ebd4a666544061 GIT binary patch literal 263368 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 z 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 |P$wB4Lw(=i9qy9`$g9 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%0ABU#< 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≷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 z zWBvv!HHZT$yphQKDl3Shc{m&r0_AG#nUhJIFYv#|(!uBHejQCpBG})gYL>THKI;^$ z-=$^W_@Ie%aW1YX)aU-}RgT1_ubh!~BecpL-ehCiQQ#plMUO-A z)~jZUyF_u{$+I4XN!mxR6j(V?pNn@pBb6JT0O^`>UEoUZO|G%0L+Ppb5qEx87`lN-lvvbRWX2lQgP~kPNfo_i>IW zaun@CbLpH=1k*HfgNW2I7zZEWNbaUR=G$t6fTZA@cj|Fb;O*i}`!@&q8bt(+!ST;4 zKn@P2iSl;s>PKpoUN#*~M3OvC?vI`8h6GYayc`k5D^r1om@`X|)KnN%g z7^F>$7>JC8Y@s~urOE@$@U(#%1`Ce7b*N?`PE=%e%}7`tLI(8d{vxB40UJfamLQ=l z2p^F&)xfPGEs<4jKxF~DbgL4`sNW&p2i|2pDl60x+$3``RV$Lo*W2)>1rmr(WQ-A> zF`kr+kg}9m3WLc8PQR5BOrg%~4tU2(X?0`ru|MvbYj7OGW&sG{co}MnMPP7OrA`@& z9#nk4E_0mJPO~zGS3{A=JXJMx1awm3L6Fgo26&|2n9e^Ml@@?{2JG0+LzBfzwH4M# zl%WFzg$H-J=An($jtxu(?vz=8>zU+{0|_?(aKmm5DS<``ZXk@)3Xy29nD zju=NgkP|=9(u+V&L#X;wQBS?M zaz9MeOwtXcE_R%cYL_9)J0k+z(PmGuUC9KN-bsz4EZ@S&a6cj{yi!RU61e1G@l9N_ zm5}kyKnf-&_XvesYR{hgQP$8k@B;h+Ig z$iV6iDMiU1o(B~iHjNtA7uPcpa4*b}lh6T?_}1Nx=A6s5w{G>7)PF%-#23Lj5Hr@T z+iJ!mxGFcXu4=HIu6?!xGs0AY=SJPi>9T^x>NY-yukx(jQ%tbDu$t9GL(GhUh!d_o za4O}Vucll_`~5WodWv&PrN2LB03SnKSE(1d^ptSfJ~A4sT>0NowQC#str%m=kgw}S zbRQNpn6%FqO!mpPDaQ2_S9D$CnfT^E4fQ;2NQ_aFl@_u9anyW6Wsa?vkTwO~uIl$d1!2Byj z%TQfT?n~*dl(p66q*&@6UVkA~B=HrrkeO|@Hgo;h?461H$gVjdx`OM-GHxs~Umtd+ zO(xN$6U!K9{`p>iI#QZL<%w^^8vXsuE&ZJoanF&p?>3_2+$qoNT?d1|X-|ya47N6& z5IwPQ(VS}+X&Go=xc@4HG3&7BwGtfnpqqDeaTf}>Tow_>P~8` z%WGsdl*y=!q0b61X*sqY?_#ppjv8B;C1cBP9S^rZ;Zm)%3NjUm?afGC2i}oK)v-Zv zxMR@tBz38{?m`X8a5t3$r^-LAOz7@>_n&x;axi!wl@m-#?P1s2qgN`sO8mdwrOd;b zk6>Og8DMZSqaEmyEx$X&t@~%FDg?G+y-+-d*S7N#uP$u>Y4pafR z^c3S7vCEcY>M~6th=T&`$Jvb+3imP>Y>>Q;O&4Oj27)dC824dLL{#nhaZZJmp$ctcP7RE~aQ*?zbO0=mB%cthd;0K$D7f5Og^ z^8Wx)aq?Mdv$Sy`yHaq%0yOS&mSl!{43S} z0A~LHhCT%Sp)aJhwq_|0TU}_lxK5cN8?v@nBvsq zOIyHCmcKgVl76*APl7u(D#eaZ3VFq87Lo&Q_3Y%d`xI!KG8pY0Pu8(+Jm_W#WdpN@ z8&*E2o|UThki%q`5QcVc!?jYHXSF6)w`7q{Lddwus=5QxejI+u{{Xdb#En}?@!x@d z4_#kDZ*q?EuBT@nK<$Q^OB`3de%k*4vk%0t6#OmFwRknn8^YT9y2rm-@infRBje{m zDVLrGc8u}|99N5YEB*>&`&)b>@WcQmLE6544)}2=gzc>2TqDon?>0p}KJ!R(`D5C# zyiNZA1q}VOd}}J)_^aZcoLG{OD)?T|tYqgQGK8t;*YTy#HSn`JtDLl-vk#3QR*yy2 z{yY3Qy|@5*hA$OeY6KpgZSCaA`V*g8>O3|319+Rn8prlp{7SHuOnaK+M)+IeE7Av| zvso(V-*B#C_x8B`uO1JvugBe1&J`yMr=(D}3I6gZHG`@AYxwWt7(UJ7AC7)3yM+Dd z?lq}det8g@cXfK; zU-*kqpB?18V~^IRYi|fd;zovR(gzK3k@^yA6)DH<8Ym^P`p4n#+WY+n;? z9~yL-G)r4E3hDOReyeb=A!t9+Q?%`@co=$?HhGt`H@l2;$3#@<@-j_ z{n*ATTZ7%)nZdQ8`Z?n-_%HW`672r~!U_8lYTASZpY+cd_~Jz8x9+2f$KkrX{{Y1Q z0Pt`R?SFS{ZGIelDEMRHHRLST+C|mW;CA_>olueLQy$gu>cMqz-fYawPg33KMxAjh zd2qz+-GVMp=~K^58M;jRC&r)fSHJivH;ydkwAH_A&0fykvRO23F2=~9$l+cX1A+el z0?l}b#4n3~7Je*AkBZ+GJXPXiufHB3@h#ort9vZ6GOtt63eU3ee!Z#YJ8cf~W85Sy zTUvL)Paog>!^5utJq+@yllW&ey`?qK6&bye$y;gKWN(3M8V==S8LKX_LN?noZTI8! zuS3$mW=|O2kk{AN)~nx=3_0bh-3||>z9-ItVE#xf6|YvQd=4y^y{S`@IczdLP6801EhYXF|}d?N|&3hS?V%kg8daBC<7(4x@UWA>wO~ zjo-8d{5L)*(Jl?8us>zBx6@&3vh+|a@*v1*RHUQ^=T0R;5oG+~!HPs|UjB@$h z&G_X&{Y`tlrI?L2`Q?xC9Mt7)V^i`HeTOxK@sg6*>W&5o;Ji8TN5gu2f>6&f1Ljbv zjCu~W)M?%Z(Cif+$4iPbyzg#X9_F<^&>{dpKylsTCm)-CN>-h=lHi4O#sc$-<&{aa zYOv^RHa3ySWSy5{E?pKPPuGLMsUx?6UwowC^i}9EPI>qKoOh-}ZFO@zvP_8q$O1-n z`IjD>vOg*%lHSObYn7D%%Xvec-nj4i)>oHtx@siS>L%ET;7MC~!B=oN_rS#q<+mX* z?buaW@9kkGH3gdhhi(rep&a0ksj63Z>grZOka~mA{uJB4P&LffkfRx{$wE(AGgR90O1sAP*La7=gU^Hxh=79Tct^vw%6Do~S%Vs^rN_k)k_3Sph4Wp#J?bA>EG$@b}0jqSRXk870N zGF5YqdiCa-x6>Bi8gtIoJ!)J4xRSnpc2GBD?HC`8J~oPDpOJ>#g3*$>_Q~h;sxePL z?=aac$8JCaxaT-H&p(AJx|f0*Vqk4Tr{x?DPB1zCb*wfonI>Fdp+u3$Hy`gYEbcuw#)T9E14xs~fW|d03c9 zxVtmpxjD`UujTpE!hYbNFD$G9VmQF+Fnaxc>Y}iYP*pM&zGJxL9_Rl6)lz+-l(RPD zx;%5q_s8i)kQ2>w8pb11BOMAHhB(J@*NS9PM<(fQfdFN4&JKSrl@xM$!{-dbGxtYg za6h2@smS)M%5D|g3JD5A;~e9-_MizEh=4LUW6&<(cJ#@|ZVqW0b}I2CxKqawZtgv} z`qWdss%Pw0tiV%e1R=ykmDg1~EVqJdvHLD8N0~3=CtM zOPPyJA*r%}&pt26miEV2n)1M-A?DI8?`_r)YL zt20R!;_BJXJNN!n?987xF=VVP0F3T91Unpa&U$q1+w!H1=5sW*UR$;{f=4Gg>`wz6 z{c5TSCXk~`f`k^x$UnumBaU&7I%IM)!~E=zGt7|+pxCMj=Ky0I3M|6SvPYU}qC~fm zV{rVn!bu{WgSY@0dCBf;M@R7Xp&b7J+8WfhX|UtSxU+B_K^&aO3get9^*JXv3#4iD zeWfM3UAF;S7NIsel^_g~K{zKoXQ8Y2_m>(?o^=4b<&Q8xWi0ZZ?Tm1scl!Do!lg!? zl06C(;mdgw-rQMe5R04Gp>~v?v&74|l_24nf`vFZ85jidjtQ=A?)qzsk#^S(^S952 zka3RV7#RI3DH*1e-%Q}mC;{I9oDARt*8}paz8=#h)NX{+S{WfS2*SwNRyhM5cVoVI z80bwnQ&EM*DLKoRp)HE}R^s;V3`k+Ztf)(47-m0?dGDO_nq;!uB=Fb^ga%J9lsU#v z0N{NNK9pX`ai)_y*s@M8ery8!hy!mYAdctLn$9;qY_W28DOQVrJ5L8WABW&+MYdx* z({?7GbHoD@6+sACki7i?{#9U3zIN#|xtr!Q98j)dww8H7jZ_`Eei#Ga`>n~(;hMF%mojC=xQ(GuV)E3lFDo}E9CR2X z9OvGuo09{qf^`LOH?wUc0OJRYbM)&`%!PyQUz>%-@;2wG{$m^;%9Qf&I8nIB?4x!* zP!D|Zp1k_ji*em1JtT^Cc8cM5I2)I6U@`_VgWPxa_NGneOEV(L&t5TmuHMIQUc47w17e5>(j5}NEq*FWt4(R2WKGt z-n)s%exKCP3Q3QMNf>2C54R+$@t%8={b}(D;W!b22OE~xxmk_9q1^rytIpRxiExm-~u_$J@S2e zeJS32g@YDg2*D)qas6$>-0%S;4{@KyfWka0Lxku~;qsDu4^EwZ zDkRbqNRTqd6_H3M0D^J|?b{#${OMqtSe>SdU8g%ktGB*-72~x=9SbTvfMD=)NCO8I z8q86GtYmTvM)>1A^#-yhn(IN)6B4nGNg2ZB11@+30()`E+=KUu@(g5- zIxp$^&~D~}Kbpj{5D8+0mFbb#1JrX&6V$N;*0P{msiuHF2I%4v74MI{IL-!6c=hQ< z6|ijD60~GwIxQ92$~Kq9Z7?Na~|1g|Y}a z0}48HADF80O)!~bjX;gd<%e^QzsinNHz_R(uPK;|bdh$K;F3Fna&h#ej_YKxkQqd0 z2X{Fjo_OueWu08wFj=#KCeg>HKR&;qt0w5MGsKw~%PHqSpGsV%MsDTPJW3sY)0bm~ zDhC4?>CgC5thVhUx;G?X0>d48^y^fn$z1t`L0mc7PjEB(8bzLXW@mOqj#fgyA^A^C zXVi?G56h)Pin&meG}7i^xmjgD>@#F_9>0&LN?E0pj4{}Zzbh8U9E|?}F;rUWTpf>v zz%9q1{{ZWn7V1eh?~^Ic_UZ>CAEtjQ#nMctSu=9eRlH6vA3Ky}H#o@7LC-ySHF7J> zI`SZ7WOhbiK{#aqkWPOC#d9ftBRNn22bbp^$>SY4&wiA?bkf`jbIx)G-~c~UQt9%P zrlfDnXaSN-S(9p)Vv`-MfHHB|`*iEay-5R^UKL(|m*Ab8f;sLv>;C}Ps+Rh_#j1#( z42M2q<36JqAJdA`webWK!XtTFL%(Uaa7HpmJoM^LI{H-dlv9~eGBU0YQ_~+z8m%p) zQ%B^*2*}|TLg9!$;~DwC&lRb4X>B??LKZiEOl^&azX0{;t!GJTacL)%$cr3!0GUsG z+4W7auTdb9Jk##-P6BW?&I)L``O z_*AVK0dT5IAjadt9CrK#F{6xvl12*vFiw76hl&(zz>S!si~GO^(p;ZjKcJ{&b~0{} zNnGF#GvAYsdUTmtm?2|;nUQ?wb;x70=fPq@=sWO9{5`4*y@eylSIl99tMX5L zjt9O+tpaY!YQN(CVqMheC@3f!qdSrB} zR|t0yQZ*UCQV8Q6PI5o}edrRBW^7kNE2&sQ+oLRU#IN359C6U?Jb#Tqb)zC?75NzM zj#VQq*N>a1_Xo9HHi}%y`?%FcLmmes*l~;j{{ZT&-9pY;?N&6E6;~r`u5(Br} z6|{a6nsV1cl3bY?0Od&N>mCae+|1%yPn_=2J9p@{cp0lmWruW3Q)N z^TlTBa9%aUmx@VZS(|Er0XbY%5A zjU&fe*T!8weNV(*BN}Wrt>pPL2Pq>OtbL~c}sLk+oZ8eKa+l@yzhtf^mbiWk|s}8O>PNEp$sChu0tQh2F`1X(SBRvs>+HBO6J>fC&sS>_Hu?AK-4c zXX8%--}r0B(xf(?OETOvWUNkjJCqFaanl&V_2R6KXBP*dlkqJ4J@GDzJXPUs3rnJV!hnOA@e%G0t)j9=z~t%^ieAr-^wgH*x9z0PC%<5@>eb7S-m_W4n%IiMGdb zipmNea6uUu2M6g`u3Kqcr9t3x!59bmiq;FLP268Kv6jFiu^nhET#`Oe0V6%n`4rgM z$pKjB9gj69m2o2CQJvg!de-sS%!(PD$XKyB1F5Mz*ya1|3G~P~{JK+BJd%9oA2t95 zan5~z8aFbrji5otcH6};C4m+2vGqL#Az_?SK#b0a;Kg|*(_;j+}= znVaYp$^9!E?7<*cF@Otg+It#LvV}SFx*jlkR)Ad8ygA}M8C~_C4r&&HB+GgBGAPLR zE04!DMJ^Isb+`oVY!FYUtzNM42Z?l|8%^;Jp>9|1`8Q6u{Ec3__@Uz|hRspz^%ckb z#B}JUVh{UFyT4ih!j5>%ghwDaILH~z2)=6-k%;sl*3Gw#yg4`{Rrp(`NW}9koy5>E z`UP^o`0WC3hWd>A(#KiTi9a?cj^Gc#svp*YSs4t-6vemYJ$_tg-i2L>lx_#AWd8s< z**+cc)zrp4Gso7+lfvqjZvp(&$Ul`m{vG&`#wM|sOuSY=s4~ z6q!sPX&J~rBap-J{{R|UkTCgr=Ze_7@JEbnpjN!_t@=h7kn3#BGxbn%D>mizj*CD ze!i56lBJji=b$7X{h^4T=76zkCs({{`ynTLMe|bx}Ti>R8972R1utKy){H}jmv|M)Ci5j za-;?a)riGIa&A1Z$ghlK1_!2b#Z2WNC9s(2HjaPs>Vb?$+)Sj$1uO4txIqjUwEj80*bef4Z{vZj_Zi(@-x*aD?KlM(S69 z4t;AW8)@rS;Fx3PHA-Mx-h+m>C+KNanc1XXnE8VqY9lhB1hxU`N*e&VZ=ciFsXL0v zl1CXT(KB#J+H>3bRBl9by|K^8epV!%!kuc2!!lftVYZS(x=rBZ^b9%uX@!uALvk2? zCZ3}?%yJ)eQbjjn!lV?zZlaV%tAmh7p;16`hWU`>LU!k=G^=vmHskTAx`5Bukl#7RdXg^r#vieEzhCG1D}x#^q#RSruSOp_2!87-zLQJGtb!`z^$o zOz=f!n9pY;*cwnI9PcOUXtN%s!^6$8&*#-0z7dM1}C&L#~z@DV>RpGa|ME&!qK8kZvDz{7@ zsi|ocN^(wJv-s14s`M1d;d98Rc}LcdbOkezIKanBVVfkoI6k{aT2@uu7ae<^l!35H zt_bz@rjh~Kc^iIz`qbcx-|Jlc6jN3?0Qppb^raEX)M$Vg0mzN^s2RZollakWBy?t% zx#FZtX2&L`OI@qdm=JubdFGStdvc_3djZy`F#3#sG(D*{>>vT8Jw2&e0Td=FS)0h( znCYAnXtqf=Zk*@)qtH~g_EV@>rH~HUx!Sqpnu^}aB8AvzYLap3U5|mUbngxLc5Q0z?JeHsFco+bDE2+G zpHIf0C?0{}AC7iEvwV>FS5DJ3r;+8v*9{u8pyQ8}XFYnF>wYxa{2~3Lbd5UWRq-C3 zrb@4ysoF6J2zr)gWgK(Vobl4UpW(;szwt-nuZp7aOui73&p`x8FRx`-gxT&l9nHtJ zdoPMU5d1LEUQII3!M-0293UM_#Jcpz8S#QvH#qB`yBVzNy#Uwn$Hnj2`}Sb?PWlhR zpBF!f@20jfqgvWAk9VnjZ38^#CcL9VI@Cyd4zH^0llQJwS^sWGs-by z54rWM9)Nt);(L2N3tf9FWN96S0CV23AqfofIf02|ozh$oKLOIWHS67H$388*@g=>p zUClGL(3k@!kDwT-bgzZl^~$7L?3Q7~pomsN;IH?1!2N3R&JH+7v2l-^^KuhYpCpzVHt|ib{1ec<$2`QI}Z$4O=1n? zk+QMM2Icekjo*(-e$qy;h1KkNclJau1bO7&xMW~dclI$$3YaZG5uAo2p|4h-!X6!F zS!J`xL5+t6Pt;?Y(6jKqhZVSZw7Xt4$xnnZ!) zzeWN~vNf6LMgR@FCzI)lv!&b4*Ck?C$OJY?ML&*4ewnQOs=0p2o=aiy3g%fAF15%b za(?7P&13igf30*De*nBXC0MU+Zl-kM_8^D@_$W2$b{aOB04iaSBP9|vdqo;6N=xk_<7+=6bS~I z76%|QE&=?jp;%*u7sk2o($BE-`_RUtH#;n&l!;n_QA|RE%KyA4Ba&+9Qh9mgdz@m~uC- zpYTy_GU8)q==#+4hSc2VfcTANfNU{StX7z24Brk*dD&!Ybsw58*%38 z)`YnmS&7ddLO}j?6uP~{wtejRfO8E;?pcj!M;={B0=l8bC0M7mMfvXnmE-IH~h3_ZQqtZn4(Ep4(G@i`9U21 zRjheZIpt=_A#0Uz&#{JiQd>Wu{-T(MRd$YP8MDR<=a0xxr*PguILB{(dG-A1vKDC> zqy#Zgc|E&T@+KtGB@)JkqEYgYdNDZsX(YOaIPts&&H@vPs~po@N`rGp8lcX|LCa@7 zN%r)qWQ|aHu)vJNt3O)S$gX5f=0s!NwFBcB1DsP}Un+4cE=cXP6HZxoCQ6KUJ8)>u z6tPwy4B!q(<3G-e6t^tI=vQ=*JYXDUl;`LH9MrNDRW3vGoH-hfwoYLhlP06H|E#<;6LN{#*gVgbX{V5Z2-Uz(2 zv@Zmy8+iBpswI8w%M2k70bkrz!}G{ zIrrlpoqAM)c@fEt@K@#Br`+Uzl|?6)$PxgX+Dt2lIaM9UPQRuPC#@us%oVmuxd)Zo z)aToZuXNEe-0gSlE z=SqRh=1~&v3x;jP@G?et1G&XL3MG=^t{B9@nG-k%r{+4-nV0Ot=HwhI2O|UP^dHKh zx*l|j!g)6gsdvWa9AlH54!@m47~7eZa;~8K$9L17pOrm;veN?=VUrDwuHo`VM=9uRPspC#!@SSGH`ZeHa@NnOIkiMfg6pdaU_wGE_A)R`nLAaJo|i*TsCl20GdS52dMUJFZc zb*bKB>@P3~!w3}e2_%d^UYWqi>Ug84X_Dy|Tb@|b?Nf7(l=L*EH8Q z_RA)te1wwf9i)^omv1Z6u;;H&)bP})&nFajVX*Lm_OjHus?DKk)(>~7B)1z=7V5JI ze8=Z#BLtNP8NeCH83c^;7ne6WtGYMs78x^yJ0DPmaa5_{n>T_y$o^|BTvb3ba z6}E%}=26E?ZSCCBEG6ZJ$^c0q?r=#VK^*dV=N|Yz^>9rq1!}Fz$d(Ai+nQUA-dtzQ zVULsy9D8t0UVFIYw-)h8BZ>jFNFWs(K<60e0910NrGm+89_I53hf^T?#2-_@B!T!< zN$0nfnll?_LB2tZcR%4;OIDH0xuWh^OXikThTi5kFys{r&>S3+IP5deYOMr0Q6qn< z0Ph&c!Qc$%@T5(}nqNC}d4p_Z{{RRb4?eXq4J@B$X>c$IETo>^@WJ{vJ9g`ieX6bP$JsYQGP3zd#gM5S zgU)^VsNMI!?%9b$k~<6$*VC^V>sQE((@B#3rfDT&>=%1{*lhPXIUpW@AIH5iQn*Bo zH*7iDrvU!|g+(-~%d%sIjWXnPT=e|;{Hf}$t+XHoq{varWcv?X=hm85ChfAsODVT9 zkV=dzk`x1uhXWqHeW}V9$&sI6ldjS*NC0v<_0Qp&sfb;YNW^kJa<8kOMr9Zx#$uSIt83&Axho{z}M`%$4#~||aux$k3oc{nyjosB+XLNAgHf>CjG4#(l z?b55DO7=yw<^!`N5(!-Y0Cchbx%_iWEP*E6*6PiS?Jvr&1N=Gns*qeA;F5W5+fQ%y zf6uK4%8Y?{amiKyf$VTVKY;?7f*5XK*lu{>XYu@fv+Y2MqMcYbo07^K9%eED z401iWKbN&W;2q+4Rh!9?mm*;&0f-!cDyvBQ-bYeP1B^CQ0th(n4?m!(;+RN{BgRpc zc-f4w$Ru-)eTg+|Vvvz}p$HdDfaEX?cpZ8SeLCZw^x1b_9O_jAme^MTU3Re~XSV~NT>gAg+zWI} z+Vg??&7n{O`QUMifn9fbmdaTQf(dhiaf5@?83gf>)`A6%3d+vLM#J!Z4hPG}PJ{C` zEx1;V~Gt*>R6R zao@c*3$oZ(jF1RW1}irku|`cY;$Fn5xg^d`2GO0TBRL1!oYJcw-eB&=N*v?^{{YuN zOy;UFj7Y2{DtieZXcWNA%+9fbs(8o)+o$16l)V{rGbmPe#&O9VdsUR4C1Wuxic|N1 zw(O9&>@$vsj()xJ&Go{`v5`4AE@UA7fb{f&?6|O zT$cDdZz^0jLaT#=)ZpXP)Y8hbNa*sC@18oYJqCFdn$F5YI9-P!fnS(^lb`Y_-h57W zO$xSh7%&Gp#|J&S@$Xskn{!yxi&2^|Bc5z47Ckexa0%z3P1ubT05H7(z`!5V`cy!%Qy|7M$sGk> zGucSry|)PG1*U`$NIu!xdU^xTT4Px>aj{_22~-TA&nF#0$@S^|DqZ^y=*%)PZP7>< za3gbZ!TjnO0<6K8Cm7l~^H!cUjO;1X83b@Wsf3_)H~^4wfPXLL{&Psprk%uU($g z%K3b@Spt)@jAyn_VfpmwRWB`wK!MNAobl4SVNt~#@~3urj*a495qM_v?HVtL?yMZ2 znm8o|7~qeY4pq1(sI4ta;;)Q#C^l-^<-N>=Z8El*3b`1^-c<)Uu7^|bZjY$WXP(kO zFs=-$m}Blp>-g6_tb8>Vu`62LN?nU6GsLF^dhOfCOcDMys;}J5(y_~4$u-oCb#XCw zW0rH&nxOYA=VN{c7_Nrr!CLjO4I4t^7$7;xKSBj#+<0qKwKaG{{WLx&0}^O=eK1$vbkJ-6&SLfJOYFeIL&Vw zisoFk6D3>rBsA&{IXUT4EzPyUkg(vKl_|(Q&-FE2!!jIK>rlxl%eyf?{MOe) zCy66r`?k$GNK4~%XNCY1>5uWMOiKV0Bd!4Br9U@=XO}a4y+LXKv=TKd99iRn4{j-; z%O`K9d8R{h@-s@<=b;Dx0Ig3mKp00WkaD4jQg9AEIp}BrLlmS3g@-*i44iYvdSPP& zx``Sv4;zj+sR@cm$OT9a7+`ae{{ZWxL*w0YD8>ulvMe+~gh)`RHluhfyBh z0pNO57Yca<0nR;rslrgmP>f`8ngDUa9!LYGOAfx6rOxog54tiyrev~}lWEB0{xtZ{ z*|Rtq7{dWdPRig!@iIw=EJinAli$Dj^r;tgip!CPWhW=52dySlN9Um6jyVREiN+)2 za3GMqsX22X7v*fSDFboH&T;8SmW&SMZ+!9vCz>N?X^RAYhpkBqsZc@V*A$bm5lL+d zNCa*G+IJE=^x~K7@pNh2K7 z9w?NR*^IA2$9(?)jXZ)EE)V6@QUDmNsx!3XnwI3y4z<0$)A_KynjCcUr7QfZ{67%9 zX#)M8ZD8F(crjl>lPDiY2D4;1Y?Q`*D9C&U2il|!S-eLIu^Nwqw5ik}JE6B|3D1As zkTdlao^G@mV`myg%r0Bx@}(s}^f?BTd3M^(#y=VXz`}ILJawv4Xb2Pla~?oB@7pyo zkSYgN$=!ktCKV2Iib%t>szT*+>r|)Q2;8B|My$KO_dbT2S+Y(unzbw_%jANH!SGA) zFnS&+n!$y>LFd;8AD=^3q?i=hJnZjgB;y;KrVebLeXHkg!d;=hqcnLh9M`KRS0zT%}oMXjxUZ zo!v5VkH)9AdEb_U1Jp1h^rl|H_KXJVDX?2Ccp*R|xD;6jDQ$>&{I>PTH2j={=4XyY zMu(4?3lC6fN=VDS6OVQoqR9%(agto-6;tfbkLYT}sG4wNk;0HOw>%%q8LEr^(=Xs^ zM2}$-B%KefFtaSo-fSQ-OsU2ftwxzsjFI?}PI(djeV8Y>q!KaX8K-t3NI2w^`48n# zzgm-drpUu-^*t!&U@#In6uaE;T7soUABOZal=*;o4y%=FXWEEt5PvFFZN1OuMi)5; z^AvLh*(}epRS}G%rbBukN<7bMf+pxQw4N01g=XVeo;!>g&rK^!ec z^U9+bC))%1RPfxej|L?Nx$8kAEp8d4F#w~Ut~%9=>r42p#lyuJT<{oWPwP;Dx%Xga z*A-;kd9jFOh&UY!lgI0d0D>rOWQBJ^p_ueV5vcqC$*Cn6!a5mLbQ!=OrcE*5`#%t^ zva7kugOXeF=~K9vk>;`zMo*W}QhNarW^Rxw{RKWS>_P?HPe3U|Olk1O!NVhRJA+uZ z#h9Apf8W}NU%FZ{Cy+=^AUmw_ubbI{Ad{1j*Pq*%;2I4{ql zscKTdjs%(a0Yz9?9DJhHi1s)YELJl)1jGe9uqj|jJgE~4o`aJ@M3Kw7H6RX|=Cs#K z3U^A%qukThD=4@Vs~*95s{(?FT>P;TK9wwX^5>Yy{3}6x#u<(if!`F#HV!162e32& zSzzbpIQrASbI>?A^aRt)wo&|}G9Rufvg@m8xG=)M@2=zcWYf3|@=S*T8{FchiV+g- zeV}@?ReK#mdy>|=ToON+*=Up&B=+S00Q#!j`VWbahP$y4rZe+Or2asfIn}^m)F6lC zQiS)y9DZh*dwS1^(oo+{)mrmUo)4Nq{{R9qV18JrPyoSHqYcvOGJMg2*8sBh^(MUyK0N#s z@cxXNKZ5=dYi8aN%iikILMJ}2fg=&@IjrQ9U}^XV_Gi2J`|(;Y9{7(8A z+E!2x_fJtt`(*yn9suxxPl7)J^xJDz2=QOs>DIBs60abjC;-Q7``4fN+xDaQtKw}b zyg8-Ir|6n?(xT5wfz;#Coz73-1$mZ}XZD%MR5ufne8&rt%uY!)i%6(PnVa4Zv;N1l zR=5cnBcjTrWBvk7Z;g7{nkBZkknCbv)DM{U>PH_+$Fa~gIRFMCImXrGkFGP1#Lf=NA3HKA!?ZkdwggOi=|FMn## zTWR8qJTR`)(TWmHNg4?X$s!zq_hdppok={cGPSf8rGrCorNPR9A0L^k0udCA<^+-3 zlOha$2h`J~ofLpJ=hJ8(%o=bFu(6W?x+p*30R1Uh6x^8T;zV7|ijfK??<|5z8^W(W zJNKwJraZDbbq1Rw5wxYUGe+B^0ZBbNa!zSC5H7=ZjHk^XHa~U>`}OPoG_p54na|4! zk%EqZ9DiD5HrWxG@-~uL++d$!>?zG9yb~Gru|kDqV#k&A0AO{;T+zyy093fNSt5vu z8zn(ZamEfmI%-%*h*_cw_y8(9ZD7f2LvG$W5Kjs?6;@qUCqHKrGcz9SY1sjIn^^3X zCXtM}CFL#m7W?7R~iNFmBaHNnu4Mrp~qTCBmg^-3;Z1v;$RTyV4GI@~| zLipY09-l#uxgAab&T3gTCATq3RFLY$Wlc@Zp>#bZt}3s-bujDdSnV`+Ve8BuEE{1V+)c7eXOr+I*g20LQ*%3;zIo?#TRwMs3<%lePo%kC1RP z$6o&RWeNMfN;8py#d+!v^ry-$QL^rh86>)ulP4cBP(J{F#+_&p;~_}m|*1fWdx6>rD&aya+W3m-*6)*oMVb$^42nTyD@B@MlskA>rDGh zdxAr^?)=5uocjzM)H6wQC+`ixWF?nmM1bR!Aoo4`QO=o2pD{8bvpxcX>cC+Rat<?BGL@h;2}$4$Ir@}|05#UiUu9AK#}=Sh#l1d4Y? zg^lSguKbd%7<3y+^}*ZU{{XK<4u(SBX4O-}FaYB`ahhmHWoXne+m$ZSoB}@%-qgNm zP)r1EZ0F^`{4>w;qjX$$6ikl3X_7W4k`=>&{VC5S!l_$~6*%RCoOS*bQ^yCB=xPZW zB8x62WC@1y;@k+wbK8oN?(%h!giw-yh_C<*R(!gN**!yfQqrW+#q#BzMh1E@cnEXJ=q!QLzSk4DSB`5lxc!&Smo*72|A2v}BBqdX9T` z<21$YrE+;MAS2~6$&4MSr8D*CBAXqAq4({ zt1Ry=ut-oK3_!uoPu|Jt*ov3!GPFuo7C=b*!{|uEAr~g z-Pn9F$uTg)5tddbZVx{G*dK@1wX7|n(xRRyrp)&P$dX8lg2O*`PhNU^{xr=#!aX+H zMYfnT6~yxe3am1IRSYwZdFV;0V7+xOCB?*HBXCJ>0)zY`9R32bm0oR`)kcbs#D$*a zUf$yN?oykMRDd2yk5UHXfuCO4teI}EwL7zQEGUJMRK^ryFb6})&ph>`QM_yGqUzDI zD-e-3?W5ED;;Xg9(cErR8kbeTDhC^g80Y{zkHAo%?oDdZ<>f#n2`b!7p^CTnc^x<( zpYyE?7h71Pj#gtM5M|`#a50Z=xgOO_D_g0WDV#VsA!FQ6Jmieyj`b{2NfN>E8-Of7i`
)Q@sNK?7IQ4I&pAIaT!05cfBkeyR(cT9>OH0sGn=FvUB>Kl zyS*;|05uj_qE&X`(U1dyv<#1@T>4Z+-R*&tGHvA)sTn+HsN`-ZkUCS*#6#plS+dd) zz4#x>nvoYt=*3H^+=DwRl6e^QILQ1lnriuCBjq4a7_^56sX6D4e!qo9c)+?jZM%-$ z*ywjCz|T@a;C|pRDN2)g=;9|3P=NZCA*P~a6X>&z|1FSnM!kj2+8QA5%mZ4 zrX?mxB;mo6E=f5Xn>YY>;0kG&$r=$TCRf2>&<&?2^UD2dGW(lw?ZC**LllfdXL!NN zs~iFJ9ld`VwXljkjO`-?@t^+yRS`R^V8Y-M*m%{3PdEb|MnE+@h@#wcERh9gR~Q>g6NBzOY2I^$ z46)&X3>$wS^d859pKrr8UUqXRD=8{v!NTR3laFqH#)f|{Yb6Cuf#8 zS=4>i;PoI5ybtA1GDj?gqY^yRfx94c)~YjQ7oM&_9KimOub(fwg|}LFxKq@~b{;JfdKV z#3>HkebM;ztjnu|1H6wQ+M|^nz5f6znkifC>008NV z1C$K2awTE8w&1V>f$PRe{C^;O8iAzA$`gj_c*9_JKaDZ(ndS3AjzS0oF&NL6XrAn)iI`ENH-yjNsuw zsYUV-p_QF_WsOrZtmhEO5u4>w6lVjsPJbNKV4HYR9zaHOf_kvv_T!=a>LjkqZ$xMb zUCOLa8XyB}9mH+O?bo5HMdWGnlhE|Q_aD^OXPdfCV_cjQmLMp`F_G7?rzGejP{#)! zcRBCRKaE3)NtYJpLn{d6$l!tLlaEiQe*G%MGnmnc2;qSTJ9^`cXVmxq02;`7hVy!`{OBe|& zIa9jVf zQr#@fvKwgGcVXl#OA+auWP#XyaaHbZu*GezJkFs*4W!n1xpYFp=%H`AGH^-3&*}Qq zwzpDwDwC;p!QS}izA!$RtXu&}Fu78o$B7hUX$LF2oYYbqV1X6DU@`{Wezj??B)E-X znlmuz%bYLc+MF#dgi_nY!465=(KiH`BO^4dyrkG z(HWF*Msde}m0Cnn#7e-cD9OnO(;YGCS~A9k0S~(*9-Ro_3aZN#*;H&6=zA02>Hh%h z^sSQ%T+f0+$^^)FGvxf9{EmAbY8loo;4rD#9J*yOCw0ixprj-Jf1x|WAdx> zS^R`H5aWkN&V7H+zqK|WL=T0n@Xt+sN}Ca=lt}fxP>8gV#EU9DP`}D{{W3?7iK2}a{7*mX?YG( zCS#Hd?&>;r;uML&JlffP+=%(k`I~_jTwq+Os;TKs)sI{{ZXNOU*qlK1Q|-W559M zkh%rliE0=rwy77w`Iat1GgNIr?$gz;5`%)Oo6a#21;1QBX=Z-2iWp~^+ zZ6l!=Ak#B)Y1o(VoTw#={JV%y4tf*)Y09jGtcp3{jnxkJNq7fuY|$GXqBYAf9D+L0 zxkZ-&2RLHgTr)S|a!oWI10W=Sg)w9?slsDDKoqGskx3aJE(U6OP!gk0_o9~=>`f!e z<%1R6OJ@ptibQ2>Zwdwma>qIE+xpX9HD8t|0|PwsM<^4BFoI9B%DDuFm2gfCG+Z!J zv4C^b9D*rhkt9f#0DgRs0-gvQ`u%DUSR6z-JdBEKKqrnxbC+%uVC9V)&;zmm05MTZ z5=MliggcL%5(nvz>q{BTK~4z+o@s#iSz~SOi3j&jAW}4LvK9`c6Y`HrMOgv)qwCO) z^x?Uff-&xRq}9Mi=w5uO&IZAekEg9ZG}$SEUvVQpGL`;#rm80Wvh*XZ6U^dR?Zl1( zHdWB}{#7H1TI7EA%aAyg{Fj8p(U z00a-fQDy`&6p4ud9FCP{C|Y=oix$$ob|)D8IH<1R7V-eA^03O96v%`hJ@7jRBl%Hg zfMvu=B_cH1!E=F7$1<@2rT~$^WX69Qu_G3_`$z+o!Qhkp=(n{<*pD=YC+@0%D${lW zzaundn}lvaJTUY$(u!`(epm=c%HPtiKARNKy2gPE4x*!bQmUx!k{1MlS*Ikxh-toX zK2r?#8LF`$awLFlB=f~vYjYV4j!)xD1SqE@V<#q!z=lmOdzRf00QbnGlSRB(m>45w z+w$kuxAgb1P_H@0&qXJ9*V4C|!$;IK$nPv6nSN|cvdF9lxF8NF1I@p)wE+luEH=JA zbdAH{{uNF|Ww|AR0FFWIYq-~RX>_}$Xk`q$uny7q);-*}@<^gr^An+26fpg01D$1z zkC^jRq%4w^BO|qT$40fei+uKR9R1ypW1oGekIJ*Jd>BbGTbyV3UnBYAo!SGLXx)ZH zS^85`=WV7uA9~ZDNx8KoG-Lta6DdtO*=gr9f0BHk%Is)ixWwDdf zr4(eITd%bg2f7&}p`#{+BXC~+l_nx!RJIs;&=y2=QWTX=NaO23IpB_H(1|B~7`Q%% z@}R`;f~lH(b21#@AE>Bq7D*)YB66O%G^~mD$AK~t{)*$&laOj?b0^ACe+<+yU1|{x zrftLAP}dSjHnI`!tw$;;H`JF57_Kl!y-5tO4tB(&KX`x!YPw4sFe^sKY>|C)erdVZ-6E+4R zwk&&+aZXnNV0EX1(5htpYc6rUNI+mSAOO>fFzU5DkQW=#GXAHap`n&MG@mh}oCs3^ zgn9Xx{Hxs4rjzWFh^A7k!ysa$irMaE1z`b)8?nf%14e{4W^#Rbs^-uNYjg`>a%#jW zB!?tp@vAXd*~CFuuzkR%waif;-NX(%8co~?Www>mWPCC2R&?DOK)*R=B+@PY;QN9& z!Ss)x%+qGnW+!a7b2$FskmK^{NT`~B*~tozFh;-i(XmXqp4!SWBwHMlfFn{xWec>& z8dl@|=a&QW6sJ_V3I^pt*-&()WKpVK<)T&)oROCFA6l<0(T~5V#h>oNeAfQ}$8(C! zd$yIgNbJY`w=Iv)r70@w^S2&`m=(&k}+rL$S5Ve+yWB%a`dB)^7eSY*g(=5!$EavU1g)4Uh1UE*jh zGNAte9zd;&KZWzn^WNS%7V41?`)-Twd}eQRq(@E(t+07ijqA3rMy!N=#H=Sj_^RAQSv-%r$KxnUlk zYjbk#&|BNH=kWs{t#lS13Gs%gfv)Vn#S;z<%AvM({?JXQZy5r)c(; zv7y}VknVQ+mgDrT=q)W!WJjNRm~7}Uqp$|Ea!YeX7RpxoG&ag&f)Kdl0AruRr?k^$ zwS)*to_=BFGZF8{ADv#bOEs6yomujwRRo(rKD=^&Iu?6ta4pde0M0T`^X8|W6re{1 zz3eL-rf@Rk?I$D;QaWa=$#*zX@?A;?a3mp5)D8_*j&|A=$Iizm*iy|qTt)U-N|YHq z^#1_s)=k{dnpva|nZ80u5rhD4<0SFYp10EoKFlNeSn}BBszBo6-Z?`JxFLBN9lr{i z7)vmoJmN9>ngEvK@_8_^Pb@$TFjqe|J&EJ+rMJqS57d)UG)fyUJ{!=~$$4n7c`Y&* zEtcEq{uQ9PM~jG7ofP=l&f!mJ9p7k7v%b2kqqb1V3#ztZvZdV7J|o-P&9xf~ys{m+<8T8$xjdicRplln+ZDthsK7@A zpTiWgB%Wh5kHa1iI0R5Tl3h$7Wg(#2Bs>{T<{L>l!uxUkY8#vRr=Kh%jH&q)1Hk-! zswJoxDYWc~({kFE zMUn8>X4r5C<&V~-mfGvfF@=m0xn0t9KBNw5vBeUI)Hb$G15BJ?W?eumU$E_s102 zrZ`YTfLM$=bs6oz$36MurYI@9mf}Li{K1cq`B((}!>)1KmdZxi<~Ylh7z{q|9Mxmf zZs6pc0)0(BK4USScJSHhnglpEm>vX7u~sZc(34QZBO7?uJDERtm~Su~uo&t{$NvDU z=~649krZxV?>Wyn<+$9CtR)}F#B zn3y9Eo&l3M1KOjTP>CWl7upxIH(c@bsGjNFLaO%bSt}u}$*!c1_$|G}Q0+nTq)~(i z>yA(2O+yW~n`ZL)HfV+8Dr15rQvU!`#(x@QGNeVMnDdS|4%s96Qml-jk?RtZ zBfrqqmMz*zFgG&9z_WsK2XV+aIM2AxN{=zd-eNAnj1U-+&(xo4ab+=rlPrqa8QggM zaCxW0F7Vds(S_g~pH6z3ZStbl!{JHTtj6PJ4p$B`J@`2k$)i}4&1{w1gCFOBNZxzoYx)0yLDU9J(a zkkT-~>~em!N==KAG)&RMxHGg$3t-76aHBXq0X;Lo>q&9ED#^lvn~wgY(}TzOQ*JMk z5?Gv^ll!sL>E4m#kYYp*_--<}=hL2X#WtH{rD9Pb5V3btk_wd_2TXhO{HipDC!frg zG*P>q$Vrf3`W~G<_@rqH;K?Szfs*{5r}`SRV+HP~IJboPQ7#L}>UM<~$ruEa&rZEQ zp-rTMoL$DHt;NK@X10*$8EM;vLDO*^yK&EI*wdzl&wN(WvyA3RLUAGK!0V5%*A&EM zK=u~O=mtFJblMmJ(~hSN>&G=DQt8ph<%`1{O@(QUZMUfQ$@~ZD&2iSK+-#3Rl{m)D zj+W*^Ma+^ZhYVTxCyaDbMtb_zPN9C+(+Jiv8f{F4a7%3fZelpxdFlNzPSvlLauNv$ zg$5EbnEAe6n4JB6F;wK=_ft6sl9e>6-*hU~F83?~$rzBhP%u{`l0IMRPvm;j^!VN0 zS*HbIi8uiL<|ppsIrZoKYP?q05}zy0Adm^%+!g1z>&WR=mV1rBq#Bm~ASZ5849(eS@=RaJ2befg!R*@t}CPh=z92`@XiMlZ~V{SMn`Fm78WXpw(0X_b2 z@igUNK|XHw3Qr!rzpWN#bJg6i9nlJHEXd&iJ@7gGaZuc|%HT}g4cnt&dSDI?c+O}Z zU?%}`e)A9y>yLU%nIktUu`;pSf>)tDbo_;CkeY3g@4R^mfU1Tf6d)`?+zw7L#~A!- zNF_|=3}o))HwDQ$sTV##b$qMW+s&YC0 zowLnLhhS;F$;(6lxrzHwCk(5-F;{{Src zK|?b1?Vn#mQpYqhHq$z0F^oFy9Otq1rjsGXBwLxcuIv%>k}`5|X|cBGgk~gQ4kSh# zFzfmBs3+BJmLn&gpzzXT7$E^rKkk<+o`kZ7|7QY)!`c62JMB9D}FkGx0+KHYlLVsW%boyrwUIXy^F zI``lKS+n?-Hyh)!UB$ZRfITWBuinl~PZ%u7$^bnZXvPkCF&cwROv!Hv%hX~gIV4P%i^!}9ZFuZFQme`T@mSDq-5AnuF zbL;@-<<=!tA?1-%C7f>HcgfCs{V7JLda;;*pFM|`*gvL!{Zxdiq|S`X62=}TbA<#Q zxW~6R=kug%m^{^QCvh_jJ^(}RvH1ZrA?v5>(ks5neycESB~>-tj1sp?1q zGyI?q8*#_4U-R!%%7RtW)aVAL_b4VZ$A%!QMu22vAmw;8jVrg#lBqm=t<;WxzsQ`?ewc`syMM@cYq-_wt$Jt*Zsu~0e)R!|ms6seFO zmnWee4>4W*x=9o=^DKZTF zj7B!{ayIjh$E{*P;&@7C9Zm?;jt0O(DIUY+807GILNa3~9gceb9lF$VrL-hT9Id#i+nv0(r+;e6I?(e#`$e%p zGr46M&!#c$>+MpFMdTqoq&t+D%5?{hy?Xjk;##du^);47VlqJW1b}~;^!;iHW|5-+ z$O|hB0sKUe4nLpZYMht5BvU*jNtVoR7-W&tp!cFH^kfrVCQ6JQ$VTou{{Wu2 zdrvaS8QPyAZTWR@FnB(^dQ+shv$nzn&hNVF2W~o?l0O`NbqJg^O()pPBW(!EyNTpy z0{~~J>-_1C1{uma?FF`;xW`Nrfl9?Hk+!6!=sO6~Mh&o)1Ogat3!L`H>z`_nKJX+} z1ws4Ux*YVVOwgo$O~m3L0Y5ihdt>#cm5NmcDFlm*Ga%7wyeR~hqm(P=`&A@CK2;h%es!NnegNI@= zLi8TLsH6lUCm*ZBUzl2B{NL&5_af-)l=+zVy&r+lxrhkzb+>&T{bXXkP@TS8}n* zYSem-t+8*k+Zhgd$57eFZrl^kf5Nj-W!(=j%^G87(Ahgff)Bq;kD;pV7UmM8vu!5> zc0eQ%{Y_n#TX_f&%;zbVQ~={Wut-18^rpueO8GMw@SFu)WcSGF>F#-_W;T&c_DL6) z6r~ALr1^l6#!mq7dJcoA>s3j&mg%ONLP=Ft+{BCmPu(A0xb&;C+D&Y`NRmWWAniE8 z`e*6-RaqVpTr*|Xf9;1#bk&K#q5T7e?kv{QI3m&9_)YWUq5v0If-EcA6rC91h zkTbI_hRDe4*j0Ok-5^;WMUQrJj7PsG>*-8N=&x}J`#6{qaC@j7{i?B0QCVMc;aqnZ z0DnrlsKO-=zl6xi``-Tmp{7dq`v@qdcMyd7eLK)OE328Z+Oa3fblZ-K`9I2-AreZX zaf}DS0APFZR_>6j=0FcUN}N@BhS>N|lsG4Y)9}uCtz#>a)zMw!-5J_&!>;1peuQz( zf6f4eEU=Ij1~5xMnb7`O@BaYTt11z|Ofu~R z2HH0OIKaj*P5|lnQdE5a88e>H& zhCq1@^6~+$y5XqfXPYOnD_DG=Qk@vXoN3?CGOM*EWECQXu zaB3E`ImvI%x=X7l{G@cp%(*_*S+wwZz%{a)MqH@p-U*S8Uyjs<4E)&`Cmz+aJ%YyM z`9P8|Mmp7Tr;vaI7#%*EA}k zaj;~1s6Wo7mKhO1J)Dqmc?bUhuT5{huF41l<`qg;0jy;oG<<-10gO^KyOhM)8;*IW zM2?^r9!Wk^Hl`5y&NYKaEfl#-?c1LKbL-*J3&h@kYQM8Ad}6p@$T)v5n=I zd0pTI8+bm(nxra(>x}X!0m4t8EV()3*wFGu)0t&EP@FN(Owfe^++z*SKp^$?p$bS3 zo52UtfF-y@w^JNwWFU8Z5PvF#8gw`<$GFWo5g6qkaXy^lo~x1bR&tHl3k>DtSn|7% zL+MMkEr|@I68Zdpoi$V!+&LiUH8jX>7du0H1IY@_-~`$3nuDBay?YWN$2h z+gAW*-zPMfm5`$b`3E`Y0-LdSWB^aNtrWBpX^Qc{vLHa;IKg3&gF%W#Qm+XOjt{L! zr0v{soOA=9&XHtb+jdBJ@6xF|j9A(>KqN=X^xA)=E4w$`Mr9pNITZAjN;G9Lk-_w* z>6Z^|#7+Z->J2*}C)2bOdbvxr3~{v_b^K~uuM6t1efwoU?y#$t7g|=~yL4o7Fx9j* zXk&~W;$gv1RF0LBi~s|DBC z)>NL{NUo$QZ{aS|pwxseaqK{#=bpsCh4ql+mrwg=sAwAe1Z!-qpwAh$`?(SQs&N=hvg zEm2-*{y;=y=KG`?Xof)hS}b65#Yz;igmu6j0jIJm4c<~euH2#hIIBWMXF=Yh-m$R_ zpUS75L$3?7*tUOKg)mUZCsEMT7&NIW?c5L6q4KuyB?JBAkLOZEi0)vOesAITrxX#K z56XZe5xE&v$n{=n2qUPcG*Gz1Lcf+jl^_VbZ6p2!PxGJz2v0}nwtG@-L7%m9z;MI8 zEg7J9XlO({qZ(13=9Fz6=sbV==mzc-QAGkAs!8CF&YVMztNBz$H9YRcAYwR6klw+; zpa}}0>%{^i+08aG^6)vwS}Q(wnKzK)zOoO*(McqdNddPl@{^nu2l>%Qv_W=l$6$(j z)XQp$Gl5Mv2?)*0geUk50^g9PHmz=)C8Ul$N!kr&Q83t}13Y!WrH&b98^j8s&$O@>^G5eyLShoeo z=Rg+{@F*_PfPL7ppz0-gQB-$hp)@DW^Di_Ndlwq^Ne&4#-!y*_s^GCbMLA-3;1fV| zGHGt{xID{l`2kC30BtfwS33Cp2?A(^;HiTo+cr{BnN<*MhqHFkPugZ|XuO2#$s zfz4@K_#;D#VK3Rd=@+9(^JDO=oZ?!eQS>dbK zZSy9!QUSuRb6YlE9*Q6~Y0;_lQJUC}*<%3!JaNxjwQUAiU=xo)QtC3*BxbIadZ~nr zC@TnJx&al0{D&@%Phc^`#M1;~uCbGY`Q&9JgW(s?fB-NsL3Tu`kN zI=_{;90nQd&+-)*XP6d9$vOL~GEdNVpf*?KJCAiwjPRML- z(L@m>VsU`k=k?7`7379zmT4awKuDs2bM-8Gnq)A;Bkf5y9Ax~s1M#T~#cJ6Nnv$a2 zg(*DyXA!!te(Z!~epMpbNg`&_QMezNxX0z|P|c~hh{(r*RUo{yl4jHZbzq@)F=6?3 zptDIH-psOJLo4uhg>^uGQfaHIpp2vlL`~2Z+4p9&WjH+46M;B200s)jD80h z{ArIhgKt)}SpXR-0R!|H{c}`SVEM}6XMieedDa-nibA`OBdMTm-B_}h%K{d+f;3>K zV)Z%toYNtiX@p5|!HOwYbvRu0Cj$fY{AvXeqi=R29P*} zO!A|tX%$p=J9#6vX+a@~jz{vPh^vsNfPDvS)H7T@=8QzUOk8B(vw95EFD@I*7@U!} z46V?f=L7s`A1Wl>ryt$J=VTHJnAHF|&u{*k7T=%BUYXq@GlCgY}W*^9N`p`QgKx)tiRE30u@EsR$KK*ciI&xl2z^EfQ z$s0hZArB<0<}hz8b;&$_K7)!9<`#7}o@iw!=8^YjjBqi=C<5GU7R|0CIbqpwPtymz zCS8h4kCQ(!J#kVrERn1X6sF&NsrKx1NU?$f4uiE+N{IDHXOy##xJJ@Xu;cZqQ_kGQ zR5sNtMo$C3f8|ky89U+&=-ZA@;nIYag34atDGD|y>fXPGK9xpJ_a7a@6XtDJ0l3M? zZ^-@>n`fS8m5POOcL2XA`U-*d2-FvvHUs{dp>BQgPl4f-nNir`umIc{NcA0$wE`^9 zJjnw{(v}FkW|G!P-Ym!gW*;ceCq1eaDC!DHA~_5W^k6{)gU&jW`cwDG5_xenpsIZC zq>u)A$?evH*1;>85XAQdv-gwB04KM<)~pMYBP0k${9cH|77 zPQ7Y3xP_dteCH%6!TJtqiEjhQBbqSh1S+w>#y1?}uN>40qBaj_3{oQud5Y%)>C-3l zsO4Z-&c|0Qc^n2H{{TTuiP9N1TRI$Nn*cD+Oy}04no%R<6Sb584^Tnmep&p-r8+cW z8%RMsft-_%#MPH{4)>BHCA6x&GnDPzan60lD#E-7;UkT@gCm~*0EJd8iz*-)Boow( z9^8s2kx|@TNQ;5F)V4FbAOVw;M&fPsEf5FKJzvc(lYHvOavvyQ01r9o*BvoR$dL@OkRTC*nRw?Oqw@a%8hc9^ zQRR+84E`tlSpHPj+~E>CXHv1?C^;v&Vh28kog#)M?cqSU##%jFM6hKg>^(U7Z7~_xU`PJ<<##{NAB+VR3xON8z z@ZkDYN=YL~!Om7gqq4Z3cD8~B+yGV&k+A2S=i0UHn%=;RGZTRu60E1W7$uKU$EGSJ zxRMN7+Lc(;{Hmil;0{S7o|OodtRcZBPnS8i}fn*zy zE8{0=BRD>p>sV&`K_d+Og~&h-><)Oy>&JRnn(c^rq*N?M&yjzqHE@mDo2>-5H6*{l zA1DDvNGv;giryY88QsHfk-FI?G zUc8Y^dI$F4xf>r-ZBII-8uk(-~hmw<|oMQ^-_*)fq8~c40-brt?$5nzB;}AWCx$$q;jF8Ob>AtLe-Xm~Rt#f~)i4y06qan@8{==pK0CZfr7mH@!a(0u`m1}F0^y6-9D#v zzDb~#MRt)Q*s-vYh7JJ^+gK1kcKPYUv~3H*miNR#;Vmi27?MlNPc@W|;1UA!)b*)T ziyh`!o5h|Sf)=~}+kwPx42B)gjCMOgs%`NL!wz?*qb$viOF~qE>{xPoaaRwAJT9}f z#-({+gdjy&!zzxXck5YtuA5Cl+ISJ29vB=LOr+(P0G_todW{>)?NVER(pYkoGqfi7b3Zrgi|h^LO}A8_x51RnJV zhxM&vPqO~Y(&4bWwZRPq>RV2wNjU(PZZdjf@a5gh88?z@bdg-2Dt84x+f<~~P`!d$zLI}6iA(31~v;gX3 zZ1Q&jm0(CX=~Q)nYsGNcJ@nex5~wAT-XnlBg21r+c@^mTr;A%snXk2dXF=3v7XDgY z>%S0I_`m_(fRljUzjO|@i>3IVOR<#6c)AtU(@TiabyPvL0&tHUhiUZOpkYVM39IBz zo`!R&E^Q7v@_&e0fot6tTars)#78s3{T|E8c!t*L;PDo*t=USS zde(Ii$e>^nRz(==k-*3v^vR&t3bdL&p{!1&zys|8!Qk{%Ku;sTPo;Mn-HqnIBPWDD z5#8xf;CY^8b4?_i=NyfyI$#AIxyC9RjW*8K&LKXQr!GXc_bk@)L{F-c*-^Co*aPMs z_~xq_KqEBtIXL_s@lrz5THI@ru5$ibJA>>q$9|Od@VCUPST|gaZY|qzA5MI!IL1hC zdePUs8{s*$i_a7`k#@3a_QjqUbtv|f4x5hQ7C-@+haH%Dnz!N47I-gC@a#4^C&O#F z-aY#+*Tf*YGcjgjS^}-fBn%KbcCKkkqF(N$Hj&F+>7Nv>$yxOcK}0|(Tb(v#0DBgV zg+}_HjBTM&eQ_PgBj!M!NgwbpvybatW~JhbdCOes_S%)Zu^w@f^2yK)bQ^7xj-BeS z{3H@Vc4V7U*Y03b&A-Zu{@|p@Mh_zyJYzT~Hk{a9TIVeOB-T-kVki}N9g)1hF!tOC z-T72^`h}eKY>`0ebt5Aih;C(E5Lgu%VhAG#CkHsj06FS)O-kp)NHq9&rvuTv=?5oMiP^2|>qc{t zN8&NDmTf{Nin_ z8&`d+G34~X%JuXnsV%0PKItRzCCg--?~T+9b;%%O`c*jDk$JAB$Axtbe_YgK(5=28 zrkx@G09QTo##cUvB|y)vewEcHg#IGgYX?WvJ}GFEg#Q3vbdX5Vg~mYvwzn!l!z%j{ zFi)RJqU!$uEHS<^apb-UB=L@N4|Z9!l)P+&rEg2SF={T4r-mx zO4YR=3V32~^#1@GMXME%Df=+;PBYU8&PV?MU!_grAB>+5v;zgdhx`dEPVk0pMa1JH zao|ZhoblaP73Eja>nSm58_RY3tcN5K+z@*E)j91anLNo3)+6R^ypnpc^)*nZ1+C3h zS+1v|zwHXejDPTs&Qy#u!*oM_n@{R0s(f72q?sm%Q`T()BrW% zITXe6Cem@p&wlhGTso31&fM}!pZ@?=Uo1uSnZ?-jZ9C%Ci!(cTw!%hIORU;tu@j$C ztiXMC)x`Ljd3U+u(RBN^W0C!xt-{;5$4N|Q@D=4#Jb_GXyc&utYbGlg)9u*j?@1mx z_c;e2jb|!JyQ0=INcNxjPqdV_jOtoGv1AAZzR{#PQO9SGaL3|*!hJi%z7f|ZHriK- zZ03-u-3OinkE))3O7Uo}yom>tZebYdXL!;70F7Ih#9GzZ0{pGt1nj%Eir|0bL_gB9 zbkVZLNcPnYY*s{aG05Qlbn`0gF6Bn{$lwJmILY_N8Ltqx*5|OcHx_oW+Q@?`{huVT zf8&b#Kk?eov-qjv8*+>_dzHY$3yTnlX{%{##;y5+Ow7($mm#@N+(YY-cy+YAV|f(-RGxjoBKc)MM(&A z^8y%-0meY@`PLPuigb-pV}cE4&7>bQ0Wea1MjHq8tMSco1cq27U|J?4X*{nSbnpEu zFJ{dZXg;Q?l4)&(YkphHaLa}ur#(O!BaHifYQ4mf%o}nBfsRq*;DOFK{A!T9ESo&W z7{dloMshljU(*#N8m465BW;lZ0$d%~Kj*DaB#Tl{Va;zl0VFd^a=S2GNru4n4~(D3 znt|ncRiX&l0Bu*tBrm&_MqHb-r8>co++hlpdU)PAUmj6wSLjKGc_wMkDF?{XhEE zN=RBZYiTXis3Qxob;!p!$nVFv^rTaEi51ZeD2ZfHq=HKVGC(8W)YJ&*XYz~XfG!nS zbQtUU{$j2@xK|!X2X96rKAiJSc*BWeSeqq5Ob$WF>PPwJsymrGb6n4jP^KXx0Z34N zKen0P9w<*dFD1 zAPa7euGrcR-N$Y}l|sQA4I3_UdUmUkx+7qdg&i1ifzBx+wTfv6ohm3*+{{<+4w&Qc zre@WO6NglIrYcpF1neV^T+#@`!eTe+6ZrzdjngF2WiHbU7BAgt-deCOozEGn0yZP>fsAJ-Ba@ERy$pJ7 z+6GBng@AFCvDDVphE?ed2jxaO$Q1+Jt45+w2+zi9>#}%rQxs#5DRnC}q84++v z=ZdK=oXQCDMh`p;X18Wn^7b@j=f2$k07LrKR(V+L&mAyS3fA{BaaJ*8vkTM_^)(w> zWMdhvy@8xZEwVOGQ^hUblO?e#&@!-W6e@qE3E7!7W1p7Ymz;h$q#M>Uj0py}F7&KM z9ZGUD$RPg!g;0A|92Kn=brdji2X%%8^>_%Nzs*h9cR*`MeO+{C+XF}EYjmni=LhIlll;M?5!ip<9t%L=njV@7Q~Ht&hg=T%zb`o)Xe z%t0L0-7<4{rAZmuarLR6MHiNzXjVIc!zcBidzI{bXQ-n26GV=r@&*NM={_%sfEMyR zH#~v>191A}1Nv4C&w{lGm`NLC9)t{oP>mZ`wqVH?anOeYADN)Z#iL`ylUrQewaiy6 z@}S!zc}Srf(;VmO4Pwc0a~hQ_80YVv57RYr4NFvo9y`lKaUjEqBkTCpIqt24Y-B0z zO*;uThQ)FF&pg5dFIF8zK3j`hfwmdSN_q!OgZR{O%L=h7K?GomLmXxxy$YPEts^Z4 zmCCo89;14VEK!FMkDRAr>sZ%XH12k?9M?!LW&kTWAx>0hrB5~T7)*u~Yz`ET2fjUO zWj2|oELt%1y%ss55z65h3}uIZdREgfEM^g1#S)hP09Mh*}1H}<%&!C<>ofIqr8 z6xkKA(wc9m(|0RsDCWDd^-Mo-z1QC=JSflmN;p zGJDdNT&#n)3_V2v1By`W6sUFs{gX{*Rgk85>}kL;85984l@$(VVBL<;Ka~*$WG}m( z=hmIL^k5IvQ)J_qz#i0^Oa;h24HUph>jLN06GbjafuPqAMZns>?$m93zreqVsCL7R z%|1_XsY#fD`9UMzu>w!ENO}`V=SY2irjUIpLNjy~X=nfpjB?Hg<4#6}d1oa03Ve2M z<0NO=tih!_au9wrHjzp#m0n2vy~zna-n0h!GEfFT!Usy%w$U51k)GgH`wt7+EP_em zEdl*~G}l9yu<*N0D%--zK9}; zqm83Y&AIT3xE;C-;-!yGf*DmHm1Jf($mvkqW{MG8Bc9Q`6Ja6qwLS7VJtUR6{4{;>e>#;eyswr(6V#T@KN?Nh50pcuL`DqK zXZz*JG~}_06#%@C{_~P)!saebHSmm1-z^EXWWqibTH}{7Io=__ja>t*&lg%e7F(k`3HxR{yi2=aC z01W+dIsIxkzmby?IpASSa>M9))D09e-k^Y$h!48C%OAq7!(?VwXy7-AQw9VVi|L z_hb13Q_UtjGexyKM2~bb{HLRIAFV?AysV|6k8?UU>6QJbk7E>!jEYd$$7 zX;w*hFjJg`;MA8Iq_Q{56l;!*P!sym%8E$1_jhtA03D~M)y`@uC15cwN3QCrB(wQX zarT5v^^Z;!kzWIG zmGXL(Oy}{Y&kDzCk`Oo;jZ0*K_+WmO8qJUOn84@_16z|Y*&s*C=bxLcI$Nt<#yef) zY{M~9Fnx&_HCW9WC@~H};{u%1#_Ag4@esF7oJBaI(Ru%cc^5e>9 z7$oFlzd_fpw- zn6uB~deF=^hiJCo-u7ym=jvvL%-&; zW>7zffDKBj7R{z;`BDZlGVD)pU^~-Mv2LtljX)iC^G+p)K3kt)g#Q5gzZxvSaGFGg zfeNd)=E2DW@)YPq$*?4F#JdALj;Eht)RXKu^`?WLnN{Ou$YgLbPDVbR>BXH6<;Y{f zBZ7UY0W;jYl0fUym~Idg8_047cB-78raS(g;)QA2HHoBPkuKPgn4P1p26^k6NLp7V zWl%z&lo#92^Q&7Hwk5<{H?uHM<8e7T0GyAny+UgIarSn8l zuJ>+mfr%LBj&gc+sNsS+kg#Tq6Tx*SA6!!tjmNao?eb!F+qh&Y+n;`MQ^7P)TNysf zDUl>Rd4p>&VlX{O{{TGHFxWamNtCfJes&-LI{{X0po$}jCM+|-Y-9=utt`_+9k^LsFP$dPzJzpWNP zOfCVH+_)zsG4$YnLOG`io+#C$!j?FgJAXO2`cxd+iv+>v3r{#KYxL=Io9?lz_(^u?Hs^ z#{)U4uO!kueo#_IH!x5+;5Go@bin#jd7I%46l%jCGZTP4`eLi5qhoI@aY=I^ZQnB5 zjmI7N;A62oa85bEC6XH4)3wsg%)zH7IEmaCftTm*jP_o8BZRE9>2z)1IhQtY*bI; z2^ldQS=__tj!Y0RbI{gUm&%KPLgy+DI3VMaKhG4#zP3S$^&5EK8QSxx&w9wc@n(@{DN}sXG-U5cVJ*9lr_;Em zCyP?%JDDwXnF8Beyt6&j=@AMTDFJyWCjfm#J2NMUoy}Ka<%e>+fX5&fBi^2@)36b! zIAO5920G{I{{YvnF5}`Zp?d^|-$IfjlEIZ4LJ(~kJpdUXXVi{+RNi02ZxAp1O7z`M zHIax%wt_^*1fQ8P&H?XE%!gW|I>I83F${%yC0LR$bNuQVbqfgP`#Rpi<}6#Lw~A#g zA0To%<0K6IJ!_oOyb{-(CHPlQ^v zoy5@US_?y`+=#{Xwv!~9gU=c`ki|2?=&++QASZTloOQ@KS)8RQZp53%9vZW`7N=7) z%zi;{Z){n~Cx8?ZS-Bkt;a4ov#W%NuOpn02y_3w3Bnz!swV$0B7-my00RtdsKg27$ z@TZBq8}Rd3f?Wf`J{;05LCmv6H1@i6>cGfF^Sc}nG8Y7ZdJ|3fllx6wYg1h4{sgvb zZ8AAoqSPj`gY9=Ehy|SOX!*c9R19YT(?Bf0pvMhDPh&frjqZozl)X06=vI(Qs;380 zT#&$R#~FV7uLC4!t!emU;g5{GQT?fLf8wnJNlP0+G8?(m_osMP0GW3v83Q2-?sWvO zBy*N}uZTQZd;Ohl1ov~gk-Fksp+2vcNYH(7E4UhFy$6IZV*6)>?XIovV~sSsT_QG$ z{y&kPLn`51uI9jHA)YK}oRQw1tf3hwi6x`cH}Ey0$WL_BrnJC0# z1&7O%l6vDKTb9>S)?ZKXH2Uq$gc3-K`jyOZ$#OTHqy=KDh1<^=Jdg!z>zbd9r=7Ix z(IQ#E?w0W_rL+pG&^8lj8-j-CrfUu3lEkF(>DUT5KWWL&eix@bv)ofvE=5G+5tepP zX?HGW(P4&lSm%yGJ6thlIO0Z7;{`E{3}^DUe7Z)YA6LHco}FzAL%uk4yBMHdgq#zF z`T87ZCc9sTUk^^VtTo=IZNZW`Bf(~28b)KzJxMYG4?P;W&xLljTGhN`P<4?av5r?p z8C(;L5$TR-l~omTsKLrf+^M75U1>5yr&`33A2p$fh@uDsrd5F>ITAXKxBz`?ow?Qg zV#~7g#Fwm$Ps%O`QSF@W{*~^&3h;)Lt>{*|z_E$Urb6$wHapgA54@)YV}QW)?^gU< z@FT&VH@!N>uRZ;|&fBM&&hRTref~^mp1AtfA6WP8V_NjC-I?Pa1&d$tUF-NmRM&MW zbcrq@ySuUe)sS0xkqIM?XNA6Sq$?n0`S=A$83d0^bRL!9?}lCt@I8ZAXc~Np6s*5$xSr*tntW#gnSlUglYqF- zYT6n^FuO|}K$j)hssWRpym#lVM5{h)Ayc5#H9RPM0M>NNYmI*I#PH2)Wf_(YmNEk( zzsZa-0YURP!#009trx@nRCtS1@P4bPt-aI_dA%kyyyP2FQ033GD9eN&lRj8w(T&JH;@b}_H)L&=USS(&( z@`U$8Ad$uZ8T~pMMEE=7=Wt}!?a@aVOP5paoF+g0RqAo-I&JO0`gus&JGC)@xZJC^ z<}J7pfJgv;cdw*(*H-qHcelb!s=G>v&$XFyPSwfV=s7+81!MK9{mFFGcV`W2@Q=oR z74Y@{0Ew;E8-u5`bKRmz^TQWHc^M!bjC~bY^G; zYwNpj5Zh~(pJ>zWWoS_0gT=TG+@4hD*pXD5L-3ZM%-V;7G?|khypgn+vcoy&3(qyW z#5m|*u!-``&Y5ATcxpzP-Wh~J8H|doA1pD~t~2^o4JX5vsK)9GbwO{5nNlUrG6zpi zdiLwbTK10^cn86^KOQXn6*iP@bd5_)OSvs9a}g2|Z~#>U<@usRw;j)@tNtVXo-`d7 zP1W^p3wWbYNrsmrM`w4YM=&Ug&E*MxQn~5C$-vHOtV>#$N|WZYJXU`P>KAtpf2Qq0 zBmB#pWaGcBHS}Fh)lBx9kc_TX%Dw<2)Q?K-d;#E_?;PlJYua|DC`dIXwKl5?HgOzI zA9Ffzcae`_>%^Le!0(BZTF<8FnrqzQon~9vt?kNvraah;4xg2M-=zr8@(1=`tvXixC=Ap$u@x{e7|cXc4L zH~{hvJ?qt>{h$1GtLoBCsy&^ZtEe;Hmx^LMv?z)rjk3e!+DYda>s>d8KWDFp_BK(`D!u3!gST`kyp2 zej9~yy5H=Rs4SvS4EXC#pMG&2<)p9>K_L9f95CapTB{cBk(;L^tj{cp?8g(^!sG%$ z0LV$}{pQI(L+x8Ou<5tDJ<-0o2IRzEG%f%rtHAA&er%6_rCrwk1pHR;^pYFj2}y9V zAN87i@!SGGy@=Sh4;?`1SpNXovfIh!-FdLd5)8vMTSx>E$ZQdj&px1zDwRmKPa|71 zGQ#;Skj1>5wiv5$yl1C=qwqgUm2NKOk)&Z1nHdXl60j%VA-Ln)+ZCFw@UV}{2X23h z8OX=u(0)|!w1^^7A}mH!am#haFiG#<(zZ_JHzclY{l3ljeX3aF%9b)J5UI{d&OToM z0R4Jxz?(#4YSN*$a0!-WR%APlK|Oi{-?d}4`zBHu3Wi?jIBw&S!T$gnmfHFRwklYK zU{_>nLXp?89Fx@Ny(=LqozZ&!))@z!_JzW)%400K&wOP4e-C=CCB1-8o(Ez$C5b<- zX>BjGm0gK@eE|#(*rfAgUV32s%0D_h<&-U~I_0#0O1w3(jmP)0K*kP9$FDukR7*`W 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 0: + mask = ((lane_xs[:start] >= 0.) & + (lane_xs[:start] <= 1.)).cpu().detach().numpy()[::-1] + mask = ~((mask.cumprod()[::-1]).astype(np.bool)) + lane_xs[:start][mask] = -2 + if end < len(self.prior_ys) - 1: + lane_xs[end + 1:] = -2 + + lane_ys = self.prior_ys[lane_xs >= 0].clone() + lane_xs = lane_xs[lane_xs >= 0] + lane_xs = lane_xs.flip(axis=0).astype('float64') + lane_ys = lane_ys.flip(axis=0) + + lane_ys = (lane_ys * + (self.ori_img_h - self.cut_height) + self.cut_height + ) / self.ori_img_h + if len(lane_xs) <= 1: + continue + points = paddle.stack( + x=(lane_xs.reshape([-1, 1]), lane_ys.reshape([-1, 1])), + axis=1).squeeze(axis=2) + lane = Lane( + points=points.cpu().numpy(), + metadata={ + 'start_x': lane[3], + 'start_y': lane[2], + 'conf': lane[1] + }) + lanes.append(lane) + return lanes + + def lane_nms(self, predictions, scores, nms_overlap_thresh, top_k): + """ + NMS for lane detection. + predictions: paddle.Tensor [num_lanes,conf,y,x,lenght,72offsets] [12,77] + scores: paddle.Tensor [num_lanes] + nms_overlap_thresh: float + top_k: int + """ + # sort by scores to get idx + idx = scores.argsort(descending=True) + keep = [] + + condidates = predictions.clone() + condidates = condidates.index_select(idx) + + while len(condidates) > 0: + keep.append(idx[0]) + if len(keep) >= top_k or len(condidates) == 1: + break + + ious = [] + for i in range(1, len(condidates)): + ious.append(1 - line_iou( + condidates[i].unsqueeze(0), + condidates[0].unsqueeze(0), + img_w=self.img_w, + length=15)) + ious = paddle.to_tensor(ious) + + mask = ious <= nms_overlap_thresh + id = paddle.where(mask == False)[0] + + if id.shape[0] == 0: + break + condidates = condidates[1:].index_select(id) + idx = idx[1:].index_select(id) + keep = paddle.stack(keep) + + return keep + + def get_lanes(self, output, as_lanes=True): + """ + Convert model output to lanes. + """ + softmax = nn.Softmax(axis=1) + decoded = [] + + for predictions in output: + if len(predictions) == 0: + decoded.append([]) + continue + threshold = self.conf_threshold + scores = softmax(predictions[:, :2])[:, 1] + keep_inds = scores >= threshold + predictions = predictions[keep_inds] + scores = scores[keep_inds] + + if predictions.shape[0] == 0: + decoded.append([]) + continue + nms_predictions = predictions.detach().clone() + nms_predictions = paddle.concat( + x=[nms_predictions[..., :4], nms_predictions[..., 5:]], axis=-1) + + nms_predictions[..., 4] = nms_predictions[..., 4] * self.n_strips + nms_predictions[..., 5:] = nms_predictions[..., 5:] * ( + self.img_w - 1) + + keep = self.lane_nms( + nms_predictions[..., 5:], + scores, + nms_overlap_thresh=self.nms_thres, + top_k=self.max_lanes) + + predictions = predictions.index_select(keep) + + if predictions.shape[0] == 0: + decoded.append([]) + continue + predictions[:, 5] = paddle.round(predictions[:, 5] * self.n_strips) + if as_lanes: + pred = self.predictions_to_pred(predictions) + else: + pred = predictions + decoded.append(pred) + return decoded + + def __call__(self, lanes_list): + lanes = self.get_lanes(lanes_list) + return lanes diff --git a/deploy/python/infer.py b/deploy/python/infer.py index 1c7be6373..dc0922bb3 100644 --- a/deploy/python/infer.py +++ b/deploy/python/infer.py @@ -33,9 +33,10 @@ sys.path.insert(0, parent_path) from benchmark_utils import PaddleInferBenchmark from picodet_postprocess import PicoDetPostProcess -from preprocess import preprocess, Resize, NormalizeImage, Permute, PadStride, LetterBoxResize, WarpAffine, Pad, decode_image +from preprocess import preprocess, Resize, NormalizeImage, Permute, PadStride, LetterBoxResize, WarpAffine, Pad, decode_image, CULaneResize from keypoint_preprocess import EvalAffine, TopDownEvalAffine, expand_crop -from visualize import visualize_box_mask +from clrnet_postprocess import CLRNetPostProcess +from visualize import visualize_box_mask, imshow_lanes from utils import argsparser, Timer, get_current_memory_mb, multiclass_nms, coco_clsid2catid # Global dictionary @@ -43,7 +44,7 @@ SUPPORT_MODELS = { 'YOLO', 'PPYOLOE', 'RCNN', 'SSD', 'Face', 'FCOS', 'SOLOv2', 'TTFNet', 'S2ANet', 'JDE', 'FairMOT', 'DeepSORT', 'GFL', 'PicoDet', 'CenterNet', 'TOOD', 'RetinaNet', 'StrongBaseline', 'STGCN', 'YOLOX', 'YOLOF', 'PPHGNet', - 'PPLCNet', 'DETR', 'CenterTrack' + 'PPLCNet', 'DETR', 'CenterTrack', 'CLRNet' } @@ -713,6 +714,112 @@ class DetectorPicoDet(Detector): return result +class DetectorCLRNet(Detector): + """ + Args: + model_dir (str): root path of model.pdiparams, model.pdmodel and infer_cfg.yml + device (str): Choose the device you want to run, it can be: CPU/GPU/XPU, default is CPU + run_mode (str): mode of running(paddle/trt_fp32/trt_fp16) + batch_size (int): size of pre batch in inference + trt_min_shape (int): min shape for dynamic shape in trt + trt_max_shape (int): max shape for dynamic shape in trt + trt_opt_shape (int): opt shape for dynamic shape in trt + trt_calib_mode (bool): If the model is produced by TRT offline quantitative + calibration, trt_calib_mode need to set True + cpu_threads (int): cpu threads + enable_mkldnn (bool): whether to turn on MKLDNN + enable_mkldnn_bfloat16 (bool): whether to turn on MKLDNN_BFLOAT16 + """ + + def __init__( + self, + model_dir, + device='CPU', + run_mode='paddle', + batch_size=1, + trt_min_shape=1, + trt_max_shape=1280, + trt_opt_shape=640, + trt_calib_mode=False, + cpu_threads=1, + enable_mkldnn=False, + enable_mkldnn_bfloat16=False, + output_dir='./', + threshold=0.5, ): + super(DetectorCLRNet, self).__init__( + model_dir=model_dir, + device=device, + run_mode=run_mode, + batch_size=batch_size, + trt_min_shape=trt_min_shape, + trt_max_shape=trt_max_shape, + trt_opt_shape=trt_opt_shape, + trt_calib_mode=trt_calib_mode, + cpu_threads=cpu_threads, + enable_mkldnn=enable_mkldnn, + enable_mkldnn_bfloat16=enable_mkldnn_bfloat16, + output_dir=output_dir, + threshold=threshold, ) + + deploy_file = os.path.join(model_dir, 'infer_cfg.yml') + with open(deploy_file) as f: + yml_conf = yaml.safe_load(f) + self.img_w = yml_conf['img_w'] + self.ori_img_h = yml_conf['ori_img_h'] + self.cut_height = yml_conf['cut_height'] + self.max_lanes = yml_conf['max_lanes'] + self.nms_thres = yml_conf['nms_thres'] + self.num_points = yml_conf['num_points'] + self.conf_threshold = yml_conf['conf_threshold'] + + def postprocess(self, inputs, result): + # postprocess output of predictor + lanes_list = result['lanes'] + postprocessor = CLRNetPostProcess( + img_w=self.img_w, + ori_img_h=self.ori_img_h, + cut_height=self.cut_height, + conf_threshold=self.conf_threshold, + nms_thres=self.nms_thres, + max_lanes=self.max_lanes, + num_points=self.num_points) + lanes = postprocessor(lanes_list) + result = dict(lanes=lanes) + return result + + def predict(self, repeats=1, run_benchmark=False): + ''' + Args: + repeats (int): repeat number for prediction + Returns: + result (dict): include 'boxes': np.ndarray: shape:[N,6], N: number of box, + matix element:[class, score, x_min, y_min, x_max, y_max] + ''' + lanes_list = [] + + if run_benchmark: + for i in range(repeats): + self.predictor.run() + paddle.device.cuda.synchronize() + result = dict(lanes=lanes_list) + return result + + for i in range(repeats): + # TODO: check the output of predictor + self.predictor.run() + lanes_list.clear() + output_names = self.predictor.get_output_names() + num_outs = int(len(output_names) / 2) + if num_outs == 0: + lanes_list.append([]) + for out_idx in range(num_outs): + lanes_list.append( + self.predictor.get_output_handle(output_names[out_idx]) + .copy_to_cpu()) + result = dict(lanes=lanes_list) + return result + + def create_inputs(imgs, im_info): """generate input for different model type Args: @@ -965,6 +1072,16 @@ def get_test_images(infer_dir, infer_img): def visualize(image_list, result, labels, output_dir='output/', threshold=0.5): # visualize the predict result + if 'lanes' in result: + print(image_list) + for idx, image_file in enumerate(image_list): + lanes = result['lanes'][idx] + img = cv2.imread(image_file) + out_file = os.path.join(output_dir, os.path.basename(image_file)) + # hard code + lanes = [lane.to_array([], ) for lane in lanes] + imshow_lanes(img, lanes, out_file=out_file) + return start_idx = 0 for idx, image_file in enumerate(image_list): im_bboxes_num = result['boxes_num'][idx] @@ -1013,6 +1130,8 @@ def main(): detector_func = 'DetectorSOLOv2' elif arch == 'PicoDet': detector_func = 'DetectorPicoDet' + elif arch == "CLRNet": + detector_func = 'DetectorCLRNet' detector = eval(detector_func)( FLAGS.model_dir, diff --git a/deploy/python/preprocess.py b/deploy/python/preprocess.py index 6f1a5a2a1..1936d3e49 100644 --- a/deploy/python/preprocess.py +++ b/deploy/python/preprocess.py @@ -14,6 +14,7 @@ import cv2 import numpy as np +import imgaug.augmenters as iaa from keypoint_preprocess import get_affine_transform from PIL import Image @@ -509,6 +510,32 @@ class WarpAffine(object): return inp, im_info +class CULaneResize(object): + def __init__(self, img_h, img_w, cut_height, prob=0.5): + super(CULaneResize, self).__init__() + self.img_h = img_h + self.img_w = img_w + self.cut_height = cut_height + self.prob = prob + + def __call__(self, im, im_info): + # cut + im = im[self.cut_height:, :, :] + # resize + transform = iaa.Sometimes(self.prob, + iaa.Resize({ + "height": self.img_h, + "width": self.img_w + })) + im = transform(image=im.copy().astype(np.uint8)) + + im = im.astype(np.float32) / 255. + # check transpose is need whether the func decode_image is equal to CULaneDataSet cv.imread + im = im.transpose(2, 0, 1) + + return im, im_info + + def preprocess(im, preprocess_ops): # process image by preprocess_ops im_info = { diff --git a/deploy/python/visualize.py b/deploy/python/visualize.py index 5d4ea4de1..e964ec05d 100644 --- a/deploy/python/visualize.py +++ b/deploy/python/visualize.py @@ -577,3 +577,63 @@ def visualize_vehicle_retrograde(im, mot_res, vehicle_retrograde_res): draw.text((xmax + 1, ymin - th), text, fill=(0, 255, 0)) return im + + +COLORS = [ + (255, 0, 0), + (0, 255, 0), + (0, 0, 255), + (255, 255, 0), + (255, 0, 255), + (0, 255, 255), + (128, 255, 0), + (255, 128, 0), + (128, 0, 255), + (255, 0, 128), + (0, 128, 255), + (0, 255, 128), + (128, 255, 255), + (255, 128, 255), + (255, 255, 128), + (60, 180, 0), + (180, 60, 0), + (0, 60, 180), + (0, 180, 60), + (60, 0, 180), + (180, 0, 60), + (255, 0, 0), + (0, 255, 0), + (0, 0, 255), + (255, 255, 0), + (255, 0, 255), + (0, 255, 255), + (128, 255, 0), + (255, 128, 0), + (128, 0, 255), +] + + +def imshow_lanes(img, lanes, show=False, out_file=None, width=4): + lanes_xys = [] + for _, lane in enumerate(lanes): + xys = [] + for x, y in lane: + if x <= 0 or y <= 0: + continue + x, y = int(x), int(y) + xys.append((x, y)) + lanes_xys.append(xys) + lanes_xys.sort(key=lambda xys: xys[0][0] if len(xys) > 0 else 0) + + for idx, xys in enumerate(lanes_xys): + for i in range(1, len(xys)): + cv2.line(img, xys[i - 1], xys[i], COLORS[idx], thickness=width) + + if show: + cv2.imshow('view', img) + cv2.waitKey(0) + + if out_file: + if not os.path.exists(os.path.dirname(out_file)): + os.makedirs(os.path.dirname(out_file)) + cv2.imwrite(out_file, img) \ No newline at end of file diff --git a/ppdet/data/culane_utils.py b/ppdet/data/culane_utils.py new file mode 100644 index 000000000..ea8c94809 --- /dev/null +++ b/ppdet/data/culane_utils.py @@ -0,0 +1,130 @@ +import math +import numpy as np +from imgaug.augmentables.lines import LineString +from scipy.interpolate import InterpolatedUnivariateSpline + + +def lane_to_linestrings(lanes): + lines = [] + for lane in lanes: + lines.append(LineString(lane)) + + return lines + + +def linestrings_to_lanes(lines): + lanes = [] + for line in lines: + lanes.append(line.coords) + + return lanes + + +def sample_lane(points, sample_ys, img_w): + # this function expects the points to be sorted + points = np.array(points) + if not np.all(points[1:, 1] < points[:-1, 1]): + raise Exception('Annotaion points have to be sorted') + x, y = points[:, 0], points[:, 1] + + # interpolate points inside domain + assert len(points) > 1 + interp = InterpolatedUnivariateSpline( + y[::-1], x[::-1], k=min(3, len(points) - 1)) + domain_min_y = y.min() + domain_max_y = y.max() + sample_ys_inside_domain = sample_ys[(sample_ys >= domain_min_y) & ( + sample_ys <= domain_max_y)] + assert len(sample_ys_inside_domain) > 0 + interp_xs = interp(sample_ys_inside_domain) + + # extrapolate lane to the bottom of the image with a straight line using the 2 points closest to the bottom + two_closest_points = points[:2] + extrap = np.polyfit( + two_closest_points[:, 1], two_closest_points[:, 0], deg=1) + extrap_ys = sample_ys[sample_ys > domain_max_y] + extrap_xs = np.polyval(extrap, extrap_ys) + all_xs = np.hstack((extrap_xs, interp_xs)) + + # separate between inside and outside points + inside_mask = (all_xs >= 0) & (all_xs < img_w) + xs_inside_image = all_xs[inside_mask] + xs_outside_image = all_xs[~inside_mask] + + return xs_outside_image, xs_inside_image + + +def filter_lane(lane): + assert lane[-1][1] <= lane[0][1] + filtered_lane = [] + used = set() + for p in lane: + if p[1] not in used: + filtered_lane.append(p) + used.add(p[1]) + + return filtered_lane + + +def transform_annotation(img_w, img_h, max_lanes, n_offsets, offsets_ys, + n_strips, strip_size, anno): + old_lanes = anno['lanes'] + + # removing lanes with less than 2 points + old_lanes = filter(lambda x: len(x) > 1, old_lanes) + # sort lane points by Y (bottom to top of the image) + old_lanes = [sorted(lane, key=lambda x: -x[1]) for lane in old_lanes] + # remove points with same Y (keep first occurrence) + old_lanes = [filter_lane(lane) for lane in old_lanes] + # normalize the annotation coordinates + old_lanes = [[[x * img_w / float(img_w), y * img_h / float(img_h)] + for x, y in lane] for lane in old_lanes] + # create tranformed annotations + lanes = np.ones( + (max_lanes, 2 + 1 + 1 + 2 + n_offsets), dtype=np.float32 + ) * -1e5 # 2 scores, 1 start_y, 1 start_x, 1 theta, 1 length, S+1 coordinates + lanes_endpoints = np.ones((max_lanes, 2)) + # lanes are invalid by default + lanes[:, 0] = 1 + lanes[:, 1] = 0 + for lane_idx, lane in enumerate(old_lanes): + if lane_idx >= max_lanes: + break + + try: + xs_outside_image, xs_inside_image = sample_lane(lane, offsets_ys, + img_w) + except AssertionError: + continue + if len(xs_inside_image) <= 1: + continue + all_xs = np.hstack((xs_outside_image, xs_inside_image)) + lanes[lane_idx, 0] = 0 + lanes[lane_idx, 1] = 1 + lanes[lane_idx, 2] = len(xs_outside_image) / n_strips + lanes[lane_idx, 3] = xs_inside_image[0] + + thetas = [] + for i in range(1, len(xs_inside_image)): + theta = math.atan( + i * strip_size / + (xs_inside_image[i] - xs_inside_image[0] + 1e-5)) / math.pi + theta = theta if theta > 0 else 1 - abs(theta) + thetas.append(theta) + + theta_far = sum(thetas) / len(thetas) + + # lanes[lane_idx, + # 4] = (theta_closest + theta_far) / 2 # averaged angle + lanes[lane_idx, 4] = theta_far + lanes[lane_idx, 5] = len(xs_inside_image) + lanes[lane_idx, 6:6 + len(all_xs)] = all_xs + lanes_endpoints[lane_idx, 0] = (len(all_xs) - 1) / n_strips + lanes_endpoints[lane_idx, 1] = xs_inside_image[-1] + + new_anno = { + 'label': lanes, + 'old_anno': anno, + 'lane_endpoints': lanes_endpoints + } + return new_anno diff --git a/ppdet/data/source/__init__.py b/ppdet/data/source/__init__.py index f4fef334e..be723eab5 100644 --- a/ppdet/data/source/__init__.py +++ b/ppdet/data/source/__init__.py @@ -19,6 +19,7 @@ from . import category from . import keypoint_coco from . import mot from . import sniper_coco +from . import culane from .coco import * from .voc import * @@ -29,3 +30,4 @@ from .mot import * from .sniper_coco import SniperCOCODataSet from .dataset import ImageFolder from .pose3d_cmb import * +from .culane import * diff --git a/ppdet/data/source/culane.py b/ppdet/data/source/culane.py new file mode 100644 index 000000000..977d608ba --- /dev/null +++ b/ppdet/data/source/culane.py @@ -0,0 +1,206 @@ +from ppdet.core.workspace import register, serializable +import cv2 +import os +import tarfile +import numpy as np +import os.path as osp +from ppdet.data.source.dataset import DetDataset +from imgaug.augmentables.lines import LineStringsOnImage +from imgaug.augmentables.segmaps import SegmentationMapsOnImage +from ppdet.data.culane_utils import lane_to_linestrings +import pickle as pkl +from ppdet.utils.logger import setup_logger +try: + from collections.abc import Sequence +except Exception: + from collections import Sequence +from .dataset import DetDataset, _make_dataset, _is_valid_file +from ppdet.utils.download import download_dataset + +logger = setup_logger(__name__) + + +@register +@serializable +class CULaneDataSet(DetDataset): + def __init__( + self, + dataset_dir, + cut_height, + list_path, + split='train', + data_fields=['image'], + video_file=None, + frame_rate=-1, ): + super(CULaneDataSet, self).__init__( + dataset_dir=dataset_dir, + cut_height=cut_height, + split=split, + data_fields=data_fields) + self.dataset_dir = dataset_dir + self.list_path = osp.join(dataset_dir, list_path) + self.cut_height = cut_height + self.data_fields = data_fields + self.split = split + self.training = 'train' in split + self.data_infos = [] + self.video_file = video_file + self.frame_rate = frame_rate + self._imid2path = {} + self.predict_dir = None + + def __len__(self): + return len(self.data_infos) + + def check_or_download_dataset(self): + if not osp.exists(self.dataset_dir): + download_dataset("dataset", dataset="culane") + # extract .tar files in self.dataset_dir + for fname in os.listdir(self.dataset_dir): + logger.info("Decompressing {}...".format(fname)) + # ignore .* files + if fname.startswith('.'): + continue + if fname.find('.tar.gz') >= 0: + with tarfile.open(osp.join(self.dataset_dir, fname)) as tf: + tf.extractall(path=self.dataset_dir) + logger.info("Dataset files are ready.") + + def parse_dataset(self): + logger.info('Loading CULane annotations...') + if self.predict_dir is not None: + logger.info('switch to predict mode') + return + # Waiting for the dataset to load is tedious, let's cache it + os.makedirs('cache', exist_ok=True) + cache_path = 'cache/culane_paddle_{}.pkl'.format(self.split) + if os.path.exists(cache_path): + with open(cache_path, 'rb') as cache_file: + self.data_infos = pkl.load(cache_file) + self.max_lanes = max( + len(anno['lanes']) for anno in self.data_infos) + return + + with open(self.list_path) as list_file: + for line in list_file: + infos = self.load_annotation(line.split()) + self.data_infos.append(infos) + + # cache data infos to file + with open(cache_path, 'wb') as cache_file: + pkl.dump(self.data_infos, cache_file) + + def load_annotation(self, line): + infos = {} + img_line = line[0] + img_line = img_line[1 if img_line[0] == '/' else 0::] + img_path = os.path.join(self.dataset_dir, img_line) + infos['img_name'] = img_line + infos['img_path'] = img_path + if len(line) > 1: + mask_line = line[1] + mask_line = mask_line[1 if mask_line[0] == '/' else 0::] + mask_path = os.path.join(self.dataset_dir, mask_line) + infos['mask_path'] = mask_path + + if len(line) > 2: + exist_list = [int(l) for l in line[2:]] + infos['lane_exist'] = np.array(exist_list) + + anno_path = img_path[: + -3] + 'lines.txt' # remove sufix jpg and add lines.txt + with open(anno_path, 'r') as anno_file: + data = [ + list(map(float, line.split())) for line in anno_file.readlines() + ] + lanes = [[(lane[i], lane[i + 1]) for i in range(0, len(lane), 2) + if lane[i] >= 0 and lane[i + 1] >= 0] for lane in data] + lanes = [list(set(lane)) for lane in lanes] # remove duplicated points + lanes = [lane for lane in lanes + if len(lane) > 2] # remove lanes with less than 2 points + + lanes = [sorted( + lane, key=lambda x: x[1]) for lane in lanes] # sort by y + infos['lanes'] = lanes + + return infos + + def set_images(self, images): + self.predict_dir = images + self.data_infos = self._load_images() + + def _find_images(self): + predict_dir = self.predict_dir + if not isinstance(predict_dir, Sequence): + predict_dir = [predict_dir] + images = [] + for im_dir in predict_dir: + if os.path.isdir(im_dir): + im_dir = os.path.join(self.predict_dir, im_dir) + images.extend(_make_dataset(im_dir)) + elif os.path.isfile(im_dir) and _is_valid_file(im_dir): + images.append(im_dir) + return images + + def _load_images(self): + images = self._find_images() + ct = 0 + records = [] + for image in images: + assert image != '' and os.path.isfile(image), \ + "Image {} not found".format(image) + if self.sample_num > 0 and ct >= self.sample_num: + break + rec = { + 'im_id': np.array([ct]), + "img_path": os.path.abspath(image), + "img_name": os.path.basename(image), + "lanes": [] + } + self._imid2path[ct] = image + ct += 1 + records.append(rec) + assert len(records) > 0, "No image file found" + return records + + def get_imid2path(self): + return self._imid2path + + def __getitem__(self, idx): + data_info = self.data_infos[idx] + img = cv2.imread(data_info['img_path']) + img = img[self.cut_height:, :, :] + sample = data_info.copy() + sample.update({'image': img}) + img_org = sample['image'] + + if self.training: + label = cv2.imread(sample['mask_path'], cv2.IMREAD_UNCHANGED) + if len(label.shape) > 2: + label = label[:, :, 0] + label = label.squeeze() + label = label[self.cut_height:, :] + sample.update({'mask': label}) + if self.cut_height != 0: + new_lanes = [] + for i in sample['lanes']: + lanes = [] + for p in i: + lanes.append((p[0], p[1] - self.cut_height)) + new_lanes.append(lanes) + sample.update({'lanes': new_lanes}) + + sample['mask'] = SegmentationMapsOnImage( + sample['mask'], shape=img_org.shape) + + sample['full_img_path'] = data_info['img_path'] + sample['img_name'] = data_info['img_name'] + sample['im_id'] = np.array([idx]) + + sample['image'] = sample['image'].copy().astype(np.uint8) + sample['lanes'] = lane_to_linestrings(sample['lanes']) + sample['lanes'] = LineStringsOnImage( + sample['lanes'], shape=img_org.shape) + sample['seg'] = np.zeros(img_org.shape) + + return sample diff --git a/ppdet/data/transform/__init__.py b/ppdet/data/transform/__init__.py index 08d7f64d9..568035812 100644 --- a/ppdet/data/transform/__init__.py +++ b/ppdet/data/transform/__init__.py @@ -18,6 +18,7 @@ from . import keypoint_operators from . import mot_operators from . import rotated_operators from . import keypoints_3d_operators +from . import culane_operators from .operators import * from .batch_operators import * @@ -25,8 +26,10 @@ from .keypoint_operators import * from .mot_operators import * from .rotated_operators import * from .keypoints_3d_operators import * +from .culane_operators import * __all__ = [] __all__ += registered_ops __all__ += keypoint_operators.__all__ __all__ += mot_operators.__all__ +__all__ += culane_operators.__all__ diff --git a/ppdet/data/transform/culane_operators.py b/ppdet/data/transform/culane_operators.py new file mode 100644 index 000000000..47904357d --- /dev/null +++ b/ppdet/data/transform/culane_operators.py @@ -0,0 +1,366 @@ +import numpy as np +import imgaug.augmenters as iaa +from .operators import BaseOperator, register_op +from ppdet.utils.logger import setup_logger +from ppdet.data.culane_utils import linestrings_to_lanes, transform_annotation + +logger = setup_logger(__name__) + +__all__ = [ + "CULaneTrainProcess", "CULaneDataProcess", "HorizontalFlip", + "ChannelShuffle", "CULaneAffine", "CULaneResize", "OneOfBlur", + "MultiplyAndAddToBrightness", "AddToHueAndSaturation" +] + + +def trainTransforms(img_h, img_w): + transforms = [{ + 'name': 'Resize', + 'parameters': dict(size=dict( + height=img_h, width=img_w)), + 'p': 1.0 + }, { + 'name': 'HorizontalFlip', + 'parameters': dict(p=1.0), + 'p': 0.5 + }, { + 'name': 'ChannelShuffle', + 'parameters': dict(p=1.0), + 'p': 0.1 + }, { + 'name': 'MultiplyAndAddToBrightness', + 'parameters': dict( + mul=(0.85, 1.15), add=(-10, 10)), + 'p': 0.6 + }, { + 'name': 'AddToHueAndSaturation', + 'parameters': dict(value=(-10, 10)), + 'p': 0.7 + }, { + 'name': 'OneOf', + 'transforms': [ + dict( + name='MotionBlur', parameters=dict(k=(3, 5))), dict( + name='MedianBlur', parameters=dict(k=(3, 5))) + ], + 'p': 0.2 + }, { + 'name': 'Affine', + 'parameters': dict( + translate_percent=dict( + x=(-0.1, 0.1), y=(-0.1, 0.1)), + rotate=(-10, 10), + scale=(0.8, 1.2)), + 'p': 0.7 + }, { + 'name': 'Resize', + 'parameters': dict(size=dict( + height=img_h, width=img_w)), + 'p': 1.0 + }] + return transforms + + +@register_op +class CULaneTrainProcess(BaseOperator): + def __init__(self, img_w, img_h): + super(CULaneTrainProcess, self).__init__() + self.img_w = img_w + self.img_h = img_h + self.transforms = trainTransforms(self.img_h, self.img_w) + + if self.transforms is not None: + img_transforms = [] + for aug in self.transforms: + p = aug['p'] + if aug['name'] != 'OneOf': + img_transforms.append( + iaa.Sometimes( + p=p, + then_list=getattr(iaa, aug['name'])(**aug[ + 'parameters']))) + else: + img_transforms.append( + iaa.Sometimes( + p=p, + then_list=iaa.OneOf([ + getattr(iaa, aug_['name'])(**aug_['parameters']) + for aug_ in aug['transforms'] + ]))) + else: + img_transforms = [] + self.iaa_transform = iaa.Sequential(img_transforms) + + def apply(self, sample, context=None): + img, line_strings, seg = self.iaa_transform( + image=sample['image'], + line_strings=sample['lanes'], + segmentation_maps=sample['mask']) + sample['image'] = img + sample['lanes'] = line_strings + sample['mask'] = seg + return sample + + +@register_op +class CULaneDataProcess(BaseOperator): + def __init__(self, img_w, img_h, num_points, max_lanes): + super(CULaneDataProcess, self).__init__() + self.img_w = img_w + self.img_h = img_h + self.num_points = num_points + self.n_offsets = num_points + self.n_strips = num_points - 1 + self.strip_size = self.img_h / self.n_strips + + self.max_lanes = max_lanes + self.offsets_ys = np.arange(self.img_h, -1, -self.strip_size) + + def apply(self, sample, context=None): + data = {} + line_strings = sample['lanes'] + line_strings.clip_out_of_image_() + new_anno = {'lanes': linestrings_to_lanes(line_strings)} + + for i in range(30): + try: + annos = transform_annotation( + self.img_w, self.img_h, self.max_lanes, self.n_offsets, + self.offsets_ys, self.n_strips, self.strip_size, new_anno) + label = annos['label'] + lane_endpoints = annos['lane_endpoints'] + break + except: + if (i + 1) == 30: + logger.critical('Transform annotation failed 30 times :(') + exit() + + sample['image'] = sample['image'].astype(np.float32) / 255. + data['image'] = sample['image'].transpose(2, 0, 1) + data['lane_line'] = label + data['seg'] = sample['seg'] + data['full_img_path'] = sample['full_img_path'] + data['img_name'] = sample['img_name'] + data['im_id'] = sample['im_id'] + + if 'mask' in sample.keys(): + data['seg'] = sample['mask'].get_arr() + + data['im_shape'] = np.array([self.img_w, self.img_h], dtype=np.float32) + data['scale_factor'] = np.array([1., 1.], dtype=np.float32) + + return data + + +@register_op +class CULaneResize(BaseOperator): + def __init__(self, img_h, img_w, prob=0.5): + super(CULaneResize, self).__init__() + self.img_h = img_h + self.img_w = img_w + self.prob = prob + + def apply(self, sample, context=None): + transform = iaa.Sometimes(self.prob, + iaa.Resize({ + "height": self.img_h, + "width": self.img_w + })) + if 'mask' in sample.keys(): + img, line_strings, seg = transform( + image=sample['image'], + line_strings=sample['lanes'], + segmentation_maps=sample['mask']) + sample['image'] = img + sample['lanes'] = line_strings + sample['mask'] = seg + else: + img, line_strings = transform( + image=sample['image'].copy().astype(np.uint8), + line_strings=sample['lanes']) + sample['image'] = img + sample['lanes'] = line_strings + + return sample + + +@register_op +class HorizontalFlip(BaseOperator): + def __init__(self, prob=0.5): + super(HorizontalFlip, self).__init__() + self.prob = prob + + def apply(self, sample, context=None): + transform = iaa.Sometimes(self.prob, iaa.HorizontalFlip(1.0)) + if 'mask' in sample.keys(): + img, line_strings, seg = transform( + image=sample['image'], + line_strings=sample['lanes'], + segmentation_maps=sample['mask']) + sample['image'] = img + sample['lanes'] = line_strings + sample['mask'] = seg + else: + img, line_strings = transform( + image=sample['image'], line_strings=sample['lanes']) + sample['image'] = img + sample['lanes'] = line_strings + + return sample + + +@register_op +class ChannelShuffle(BaseOperator): + def __init__(self, prob=0.1): + super(ChannelShuffle, self).__init__() + self.prob = prob + + def apply(self, sample, context=None): + transform = iaa.Sometimes(self.prob, iaa.ChannelShuffle(1.0)) + if 'mask' in sample.keys(): + img, line_strings, seg = transform( + image=sample['image'], + line_strings=sample['lanes'], + segmentation_maps=sample['mask']) + sample['image'] = img + sample['lanes'] = line_strings + sample['mask'] = seg + else: + img, line_strings = transform( + image=sample['image'], line_strings=sample['lanes']) + sample['image'] = img + sample['lanes'] = line_strings + + return sample + + +@register_op +class MultiplyAndAddToBrightness(BaseOperator): + def __init__(self, mul=(0.85, 1.15), add=(-10, 10), prob=0.5): + super(MultiplyAndAddToBrightness, self).__init__() + self.mul = tuple(mul) + self.add = tuple(add) + self.prob = prob + + def apply(self, sample, context=None): + transform = iaa.Sometimes( + self.prob, + iaa.MultiplyAndAddToBrightness( + mul=self.mul, add=self.add)) + if 'mask' in sample.keys(): + img, line_strings, seg = transform( + image=sample['image'], + line_strings=sample['lanes'], + segmentation_maps=sample['mask']) + sample['image'] = img + sample['lanes'] = line_strings + sample['mask'] = seg + else: + img, line_strings = transform( + image=sample['image'], line_strings=sample['lanes']) + sample['image'] = img + sample['lanes'] = line_strings + + return sample + + +@register_op +class AddToHueAndSaturation(BaseOperator): + def __init__(self, value=(-10, 10), prob=0.5): + super(AddToHueAndSaturation, self).__init__() + self.value = tuple(value) + self.prob = prob + + def apply(self, sample, context=None): + transform = iaa.Sometimes( + self.prob, iaa.AddToHueAndSaturation(value=self.value)) + if 'mask' in sample.keys(): + img, line_strings, seg = transform( + image=sample['image'], + line_strings=sample['lanes'], + segmentation_maps=sample['mask']) + sample['image'] = img + sample['lanes'] = line_strings + sample['mask'] = seg + else: + img, line_strings = transform( + image=sample['image'], line_strings=sample['lanes']) + sample['image'] = img + sample['lanes'] = line_strings + + return sample + + +@register_op +class OneOfBlur(BaseOperator): + def __init__(self, MotionBlur_k=(3, 5), MedianBlur_k=(3, 5), prob=0.5): + super(OneOfBlur, self).__init__() + self.MotionBlur_k = tuple(MotionBlur_k) + self.MedianBlur_k = tuple(MedianBlur_k) + self.prob = prob + + def apply(self, sample, context=None): + transform = iaa.Sometimes( + self.prob, + iaa.OneOf([ + iaa.MotionBlur(k=self.MotionBlur_k), + iaa.MedianBlur(k=self.MedianBlur_k) + ])) + + if 'mask' in sample.keys(): + img, line_strings, seg = transform( + image=sample['image'], + line_strings=sample['lanes'], + segmentation_maps=sample['mask']) + sample['image'] = img + sample['lanes'] = line_strings + sample['mask'] = seg + else: + img, line_strings = transform( + image=sample['image'], line_strings=sample['lanes']) + sample['image'] = img + sample['lanes'] = line_strings + + return sample + + +@register_op +class CULaneAffine(BaseOperator): + def __init__(self, + translate_percent_x=(-0.1, 0.1), + translate_percent_y=(-0.1, 0.1), + rotate=(3, 5), + scale=(0.8, 1.2), + prob=0.5): + super(CULaneAffine, self).__init__() + self.translate_percent = { + 'x': tuple(translate_percent_x), + 'y': tuple(translate_percent_y) + } + self.rotate = tuple(rotate) + self.scale = tuple(scale) + self.prob = prob + + def apply(self, sample, context=None): + transform = iaa.Sometimes( + self.prob, + iaa.Affine( + translate_percent=self.translate_percent, + rotate=self.rotate, + scale=self.scale)) + + if 'mask' in sample.keys(): + img, line_strings, seg = transform( + image=sample['image'], + line_strings=sample['lanes'], + segmentation_maps=sample['mask']) + sample['image'] = img + sample['lanes'] = line_strings + sample['mask'] = seg + else: + img, line_strings = transform( + image=sample['image'], line_strings=sample['lanes']) + sample['image'] = img + sample['lanes'] = line_strings + + return sample diff --git a/ppdet/engine/export_utils.py b/ppdet/engine/export_utils.py index 882dd5af6..daaa39a62 100644 --- a/ppdet/engine/export_utils.py +++ b/ppdet/engine/export_utils.py @@ -54,10 +54,12 @@ TRT_MIN_SUBGRAPH = { 'YOLOF': 40, 'METRO_Body': 3, 'DETR': 3, + 'CLRNet': 3 } KEYPOINT_ARCH = ['HigherHRNet', 'TopDownHRNet'] MOT_ARCH = ['JDE', 'FairMOT', 'DeepSORT', 'ByteTrack', 'CenterTrack'] +LANE_ARCH = ['CLRNet'] TO_STATIC_SPEC = { 'yolov3_darknet53_270e_coco': [{ @@ -215,12 +217,13 @@ def _prune_input_spec(input_spec, program, targets): def _parse_reader(reader_cfg, dataset_cfg, metric, arch, image_shape): preprocess_list = [] + label_list = [] + if arch != "lane_arch": + anno_file = dataset_cfg.get_anno() - anno_file = dataset_cfg.get_anno() + clsid2catid, catid2name = get_categories(metric, anno_file, arch) - clsid2catid, catid2name = get_categories(metric, anno_file, arch) - - label_list = [str(cat) for cat in catid2name.values()] + label_list = [str(cat) for cat in catid2name.values()] fuse_normalize = reader_cfg.get('fuse_normalize', False) sample_transforms = reader_cfg['sample_transforms'] @@ -246,6 +249,13 @@ def _parse_reader(reader_cfg, dataset_cfg, metric, arch, image_shape): 'stride': value['pad_to_stride'] }) break + elif key == "CULaneResize": + # cut and resize + p = {'type': key} + p.update(value) + p.update({"cut_height": dataset_cfg.cut_height}) + preprocess_list.append(p) + break return preprocess_list, label_list @@ -315,6 +325,20 @@ def _dump_infer_config(config, path, image_shape, model): if infer_arch in KEYPOINT_ARCH: label_arch = 'keypoint_arch' + if infer_arch in LANE_ARCH: + infer_cfg['arch'] = infer_arch + infer_cfg['min_subgraph_size'] = TRT_MIN_SUBGRAPH[infer_arch] + infer_cfg['img_w'] = config['img_w'] + infer_cfg['ori_img_h'] = config['ori_img_h'] + infer_cfg['cut_height'] = config['cut_height'] + label_arch = 'lane_arch' + head_name = "CLRHead" + infer_cfg['conf_threshold'] = config[head_name]['conf_threshold'] + infer_cfg['nms_thres'] = config[head_name]['nms_thres'] + infer_cfg['max_lanes'] = config[head_name]['max_lanes'] + infer_cfg['num_points'] = config[head_name]['num_points'] + arch_state = True + if infer_arch in MOT_ARCH: if config['metric'] in ['COCO', 'VOC']: # MOT model run as Detector diff --git a/ppdet/engine/trainer.py b/ppdet/engine/trainer.py index bfd92fd62..583712c31 100644 --- a/ppdet/engine/trainer.py +++ b/ppdet/engine/trainer.py @@ -39,13 +39,14 @@ from ppdet.core.workspace import create from ppdet.utils.checkpoint import load_weight, load_pretrain_weight from ppdet.utils.visualizer import visualize_results, save_result from ppdet.metrics import get_infer_results, KeyPointTopDownCOCOEval, KeyPointTopDownCOCOWholeBadyHandEval, KeyPointTopDownMPIIEval, Pose3DEval -from ppdet.metrics import Metric, COCOMetric, VOCMetric, WiderFaceMetric, RBoxMetric, JDEDetMetric, SNIPERCOCOMetric +from ppdet.metrics import Metric, COCOMetric, VOCMetric, WiderFaceMetric, RBoxMetric, JDEDetMetric, SNIPERCOCOMetric, CULaneMetric from ppdet.data.source.sniper_coco import SniperCOCODataSet from ppdet.data.source.category import get_categories import ppdet.utils.stats as stats from ppdet.utils.fuse_utils import fuse_conv_bn from ppdet.utils import profiler from ppdet.modeling.post_process import multiclass_nms +from ppdet.modeling.lane_utils import imshow_lanes from .callbacks import Callback, ComposeCallback, LogPrinter, Checkpointer, WiferFaceEval, VisualDLWriter, SniperProposalsGenerator, WandbCallback from .export_utils import _dump_infer_config, _prune_input_spec, apply_to_static @@ -383,6 +384,15 @@ class Trainer(object): ] elif self.cfg.metric == 'MOTDet': self._metrics = [JDEDetMetric(), ] + elif self.cfg.metric == 'CULaneMetric': + output_eval = self.cfg.get('output_eval', None) + self._metrics = [ + CULaneMetric( + cfg=self.cfg, + output_eval=output_eval, + split=self.dataset.split, + dataset_dir=self.cfg.dataset_dir) + ] else: logger.warning("Metric not support for metric type {}".format( self.cfg.metric)) @@ -1139,6 +1149,12 @@ class Trainer(object): "crops": InputSpec( shape=[None, 3, 192, 64], name='crops') }) + + if self.cfg.architecture == 'CLRNet': + input_spec[0].update({ + "full_img_path": str, + "img_name": str, + }) if prune_input: static_model = paddle.jit.to_static( self.model, input_spec=input_spec) @@ -1277,3 +1293,107 @@ class Trainer(object): logger.info("Found {} inference images in total.".format( len(images))) return all_images + + def predict_culane(self, + images, + output_dir='output', + save_results=False, + visualize=True): + if not os.path.exists(output_dir): + os.makedirs(output_dir) + + self.dataset.set_images(images) + loader = create('TestReader')(self.dataset, 0) + + imid2path = self.dataset.get_imid2path() + + def setup_metrics_for_loader(): + # mem + metrics = copy.deepcopy(self._metrics) + mode = self.mode + save_prediction_only = self.cfg[ + 'save_prediction_only'] if 'save_prediction_only' in self.cfg else None + output_eval = self.cfg[ + 'output_eval'] if 'output_eval' in self.cfg else None + + # modify + self.mode = '_test' + self.cfg['save_prediction_only'] = True + self.cfg['output_eval'] = output_dir + self.cfg['imid2path'] = imid2path + self._init_metrics() + + # restore + self.mode = mode + self.cfg.pop('save_prediction_only') + if save_prediction_only is not None: + self.cfg['save_prediction_only'] = save_prediction_only + + self.cfg.pop('output_eval') + if output_eval is not None: + self.cfg['output_eval'] = output_eval + + self.cfg.pop('imid2path') + + _metrics = copy.deepcopy(self._metrics) + self._metrics = metrics + + return _metrics + + if save_results: + metrics = setup_metrics_for_loader() + else: + metrics = [] + + # Run Infer + self.status['mode'] = 'test' + self.model.eval() + if self.cfg.get('print_flops', False): + flops_loader = create('TestReader')(self.dataset, 0) + self._flops(flops_loader) + results = [] + for step_id, data in enumerate(tqdm(loader)): + self.status['step_id'] = step_id + # forward + outs = self.model(data) + + for _m in metrics: + _m.update(data, outs) + + for key in ['im_shape', 'scale_factor', 'im_id']: + if isinstance(data, typing.Sequence): + outs[key] = data[0][key] + else: + outs[key] = data[key] + for key, value in outs.items(): + if hasattr(value, 'numpy'): + outs[key] = value.numpy() + results.append(outs) + + for _m in metrics: + _m.accumulate() + _m.reset() + + if visualize: + import cv2 + + for outs in results: + for i in range(len(outs['img_path'])): + lanes = outs['lanes'][i] + img_path = outs['img_path'][i] + img = cv2.imread(img_path) + out_file = os.path.join(output_dir, + os.path.basename(img_path)) + lanes = [ + lane.to_array( + sample_y_range=[ + self.cfg['sample_y']['start'], + self.cfg['sample_y']['end'], + self.cfg['sample_y']['step'] + ], + img_w=self.cfg.ori_img_w, + img_h=self.cfg.ori_img_h) for lane in lanes + ] + imshow_lanes(img, lanes, out_file=out_file) + + return results diff --git a/ppdet/metrics/__init__.py b/ppdet/metrics/__init__.py index 3e1b83cca..288f1581f 100644 --- a/ppdet/metrics/__init__.py +++ b/ppdet/metrics/__init__.py @@ -27,4 +27,8 @@ __all__ = metrics.__all__ + mot_metrics.__all__ from . import mcmot_metrics from .mcmot_metrics import * -__all__ = metrics.__all__ + mcmot_metrics.__all__ \ No newline at end of file +__all__ = metrics.__all__ + mcmot_metrics.__all__ + +from . import culane_metrics +from .culane_metrics import * +__all__ = metrics.__all__ + culane_metrics.__all__ \ No newline at end of file diff --git a/ppdet/metrics/culane_metrics.py b/ppdet/metrics/culane_metrics.py new file mode 100644 index 000000000..848d2c186 --- /dev/null +++ b/ppdet/metrics/culane_metrics.py @@ -0,0 +1,327 @@ +import os +import cv2 +import numpy as np +import os.path as osp +from functools import partial +from .metrics import Metric +from scipy.interpolate import splprep, splev +from scipy.optimize import linear_sum_assignment +from shapely.geometry import LineString, Polygon +from ppdet.utils.logger import setup_logger + +logger = setup_logger(__name__) + +__all__ = [ + 'draw_lane', 'discrete_cross_iou', 'continuous_cross_iou', 'interp', + 'culane_metric', 'load_culane_img_data', 'load_culane_data', + 'eval_predictions', "CULaneMetric" +] + +LIST_FILE = { + 'train': 'list/train_gt.txt', + 'val': 'list/val.txt', + 'test': 'list/test.txt', +} + +CATEGORYS = { + 'normal': 'list/test_split/test0_normal.txt', + 'crowd': 'list/test_split/test1_crowd.txt', + 'hlight': 'list/test_split/test2_hlight.txt', + 'shadow': 'list/test_split/test3_shadow.txt', + 'noline': 'list/test_split/test4_noline.txt', + 'arrow': 'list/test_split/test5_arrow.txt', + 'curve': 'list/test_split/test6_curve.txt', + 'cross': 'list/test_split/test7_cross.txt', + 'night': 'list/test_split/test8_night.txt', +} + + +def draw_lane(lane, img=None, img_shape=None, width=30): + if img is None: + img = np.zeros(img_shape, dtype=np.uint8) + lane = lane.astype(np.int32) + for p1, p2 in zip(lane[:-1], lane[1:]): + cv2.line( + img, tuple(p1), tuple(p2), color=(255, 255, 255), thickness=width) + return img + + +def discrete_cross_iou(xs, ys, width=30, img_shape=(590, 1640, 3)): + xs = [draw_lane(lane, img_shape=img_shape, width=width) > 0 for lane in xs] + ys = [draw_lane(lane, img_shape=img_shape, width=width) > 0 for lane in ys] + + ious = np.zeros((len(xs), len(ys))) + for i, x in enumerate(xs): + for j, y in enumerate(ys): + ious[i, j] = (x & y).sum() / (x | y).sum() + return ious + + +def continuous_cross_iou(xs, ys, width=30, img_shape=(590, 1640, 3)): + h, w, _ = img_shape + image = Polygon([(0, 0), (0, h - 1), (w - 1, h - 1), (w - 1, 0)]) + xs = [ + LineString(lane).buffer( + distance=width / 2., cap_style=1, join_style=2).intersection(image) + for lane in xs + ] + ys = [ + LineString(lane).buffer( + distance=width / 2., cap_style=1, join_style=2).intersection(image) + for lane in ys + ] + + ious = np.zeros((len(xs), len(ys))) + for i, x in enumerate(xs): + for j, y in enumerate(ys): + ious[i, j] = x.intersection(y).area / x.union(y).area + + return ious + + +def interp(points, n=50): + x = [x for x, _ in points] + y = [y for _, y in points] + tck, u = splprep([x, y], s=0, t=n, k=min(3, len(points) - 1)) + + u = np.linspace(0., 1., num=(len(u) - 1) * n + 1) + return np.array(splev(u, tck)).T + + +def culane_metric(pred, + anno, + width=30, + iou_thresholds=[0.5], + official=True, + img_shape=(590, 1640, 3)): + _metric = {} + for thr in iou_thresholds: + tp = 0 + fp = 0 if len(anno) != 0 else len(pred) + fn = 0 if len(pred) != 0 else len(anno) + _metric[thr] = [tp, fp, fn] + + interp_pred = np.array( + [interp( + pred_lane, n=5) for pred_lane in pred], dtype=object) # (4, 50, 2) + interp_anno = np.array( + [interp( + anno_lane, n=5) for anno_lane in anno], dtype=object) # (4, 50, 2) + + if official: + ious = discrete_cross_iou( + interp_pred, interp_anno, width=width, img_shape=img_shape) + else: + ious = continuous_cross_iou( + interp_pred, interp_anno, width=width, img_shape=img_shape) + + row_ind, col_ind = linear_sum_assignment(1 - ious) + + _metric = {} + for thr in iou_thresholds: + tp = int((ious[row_ind, col_ind] > thr).sum()) + fp = len(pred) - tp + fn = len(anno) - tp + _metric[thr] = [tp, fp, fn] + return _metric + + +def load_culane_img_data(path): + with open(path, 'r') as data_file: + img_data = data_file.readlines() + img_data = [line.split() for line in img_data] + img_data = [list(map(float, lane)) for lane in img_data] + img_data = [[(lane[i], lane[i + 1]) for i in range(0, len(lane), 2)] + for lane in img_data] + img_data = [lane for lane in img_data if len(lane) >= 2] + + return img_data + + +def load_culane_data(data_dir, file_list_path): + with open(file_list_path, 'r') as file_list: + filepaths = [ + os.path.join(data_dir, + line[1 if line[0] == '/' else 0:].rstrip().replace( + '.jpg', '.lines.txt')) + for line in file_list.readlines() + ] + + data = [] + for path in filepaths: + img_data = load_culane_img_data(path) + data.append(img_data) + + return data + + +def eval_predictions(pred_dir, + anno_dir, + list_path, + iou_thresholds=[0.5], + width=30, + official=True, + sequential=False): + logger.info('Calculating metric for List: {}'.format(list_path)) + predictions = load_culane_data(pred_dir, list_path) + annotations = load_culane_data(anno_dir, list_path) + img_shape = (590, 1640, 3) + if sequential: + results = map(partial( + culane_metric, + width=width, + official=official, + iou_thresholds=iou_thresholds, + img_shape=img_shape), + predictions, + annotations) + else: + from multiprocessing import Pool, cpu_count + from itertools import repeat + with Pool(cpu_count()) as p: + results = p.starmap(culane_metric, + zip(predictions, annotations, + repeat(width), + repeat(iou_thresholds), + repeat(official), repeat(img_shape))) + + mean_f1, mean_prec, mean_recall, total_tp, total_fp, total_fn = 0, 0, 0, 0, 0, 0 + ret = {} + for thr in iou_thresholds: + tp = sum(m[thr][0] for m in results) + fp = sum(m[thr][1] for m in results) + fn = sum(m[thr][2] for m in results) + precision = float(tp) / (tp + fp) if tp != 0 else 0 + recall = float(tp) / (tp + fn) if tp != 0 else 0 + f1 = 2 * precision * recall / (precision + recall) if tp != 0 else 0 + logger.info('iou thr: {:.2f}, tp: {}, fp: {}, fn: {},' + 'precision: {}, recall: {}, f1: {}'.format( + thr, tp, fp, fn, precision, recall, f1)) + mean_f1 += f1 / len(iou_thresholds) + mean_prec += precision / len(iou_thresholds) + mean_recall += recall / len(iou_thresholds) + total_tp += tp + total_fp += fp + total_fn += fn + ret[thr] = { + 'TP': tp, + 'FP': fp, + 'FN': fn, + 'Precision': precision, + 'Recall': recall, + 'F1': f1 + } + if len(iou_thresholds) > 2: + logger.info( + 'mean result, total_tp: {}, total_fp: {}, total_fn: {},' + 'precision: {}, recall: {}, f1: {}'.format( + total_tp, total_fp, total_fn, mean_prec, mean_recall, mean_f1)) + ret['mean'] = { + 'TP': total_tp, + 'FP': total_fp, + 'FN': total_fn, + 'Precision': mean_prec, + 'Recall': mean_recall, + 'F1': mean_f1 + } + return ret + + +class CULaneMetric(Metric): + def __init__(self, + cfg, + output_eval=None, + split="test", + dataset_dir="dataset/CULane/"): + super(CULaneMetric, self).__init__() + self.output_eval = "evaluation" if output_eval is None else output_eval + self.dataset_dir = dataset_dir + self.split = split + self.list_path = osp.join(dataset_dir, LIST_FILE[split]) + self.predictions = [] + self.img_names = [] + self.lanes = [] + self.eval_results = {} + self.cfg = cfg + self.reset() + + def reset(self): + self.predictions = [] + self.img_names = [] + self.lanes = [] + self.eval_results = {} + + def get_prediction_string(self, pred): + ys = np.arange(270, 590, 8) / self.cfg.ori_img_h + out = [] + for lane in pred: + xs = lane(ys) + valid_mask = (xs >= 0) & (xs < 1) + xs = xs * self.cfg.ori_img_w + lane_xs = xs[valid_mask] + lane_ys = ys[valid_mask] * self.cfg.ori_img_h + lane_xs, lane_ys = lane_xs[::-1], lane_ys[::-1] + lane_str = ' '.join([ + '{:.5f} {:.5f}'.format(x, y) for x, y in zip(lane_xs, lane_ys) + ]) + if lane_str != '': + out.append(lane_str) + + return '\n'.join(out) + + def accumulate(self): + loss_lines = [[], [], [], []] + for idx, pred in enumerate(self.predictions): + output_dir = os.path.join(self.output_eval, + os.path.dirname(self.img_names[idx])) + output_filename = os.path.basename(self.img_names[ + idx])[:-3] + 'lines.txt' + os.makedirs(output_dir, exist_ok=True) + output = self.get_prediction_string(pred) + + # store loss lines + lanes = self.lanes[idx] + if len(lanes) - len(pred) in [1, 2, 3, 4]: + loss_lines[len(lanes) - len(pred) - 1].append(self.img_names[ + idx]) + + with open(os.path.join(output_dir, output_filename), + 'w') as out_file: + out_file.write(output) + + for i, names in enumerate(loss_lines): + with open( + os.path.join(output_dir, 'loss_{}_lines.txt'.format(i + 1)), + 'w') as f: + for name in names: + f.write(name + '\n') + + for cate, cate_file in CATEGORYS.items(): + result = eval_predictions( + self.output_eval, + self.dataset_dir, + os.path.join(self.dataset_dir, cate_file), + iou_thresholds=[0.5], + official=True) + + result = eval_predictions( + self.output_eval, + self.dataset_dir, + self.list_path, + iou_thresholds=np.linspace(0.5, 0.95, 10), + official=True) + self.eval_results['F1@50'] = result[0.5]['F1'] + self.eval_results['result'] = result + + def update(self, inputs, outputs): + assert len(inputs['img_name']) == len(outputs['lanes']) + self.predictions.extend(outputs['lanes']) + self.img_names.extend(inputs['img_name']) + self.lanes.extend(inputs['lane_line']) + + def log(self): + logger.info(self.eval_results) + + # abstract method for getting metric results + def get_results(self): + return self.eval_results diff --git a/ppdet/modeling/architectures/__init__.py b/ppdet/modeling/architectures/__init__.py index eb5ff75c2..ad60f0f24 100644 --- a/ppdet/modeling/architectures/__init__.py +++ b/ppdet/modeling/architectures/__init__.py @@ -42,6 +42,7 @@ from . import yolof from . import pose3d_metro from . import centertrack from . import queryinst +from . import clrnet from .meta_arch import * from .faster_rcnn import * @@ -74,4 +75,5 @@ from .yolof import * from .pose3d_metro import * from .centertrack import * from .queryinst import * -from .keypoint_petr import * \ No newline at end of file +from .keypoint_petr import * +from .clrnet import * \ No newline at end of file diff --git a/ppdet/modeling/architectures/clrnet.py b/ppdet/modeling/architectures/clrnet.py new file mode 100644 index 000000000..8336fd888 --- /dev/null +++ b/ppdet/modeling/architectures/clrnet.py @@ -0,0 +1,67 @@ +from .meta_arch import BaseArch +from ppdet.core.workspace import register, create +from paddle import in_dynamic_mode + +__all__ = ['CLRNet'] + + +@register +class CLRNet(BaseArch): + __category__ = 'architecture' + + def __init__(self, + backbone="CLRResNet", + neck="CLRFPN", + clr_head="CLRHead", + post_process=None): + super(CLRNet, self).__init__() + self.backbone = backbone + self.neck = neck + self.heads = clr_head + self.post_process = post_process + + @classmethod + def from_config(cls, cfg, *args, **kwargs): + # backbone + backbone = create(cfg['backbone']) + # fpn + kwargs = {'input_shape': backbone.out_shape} + neck = create(cfg['neck'], **kwargs) + # head + kwargs = {'input_shape': neck.out_shape} + clr_head = create(cfg['clr_head'], **kwargs) + + return { + 'backbone': backbone, + 'neck': neck, + 'clr_head': clr_head, + } + + def _forward(self): + # Backbone + body_feats = self.backbone(self.inputs['image']) + # neck + neck_feats = self.neck(body_feats) + # CRL Head + + if self.training: + output = self.heads(neck_feats, self.inputs) + else: + output = self.heads(neck_feats) + output = {'lanes': output} + # TODO: hard code fix as_lanes=False problem in clrnet_head.py "get_lanes" function for static mode + if in_dynamic_mode(): + output = self.heads.get_lanes(output['lanes']) + output = { + "lanes": output, + "img_path": self.inputs['full_img_path'], + "img_name": self.inputs['img_name'] + } + + return output + + def get_loss(self): + return self._forward() + + def get_pred(self): + return self._forward() diff --git a/ppdet/modeling/assigners/clrnet_assigner.py b/ppdet/modeling/assigners/clrnet_assigner.py new file mode 100644 index 000000000..59c94a0a7 --- /dev/null +++ b/ppdet/modeling/assigners/clrnet_assigner.py @@ -0,0 +1,147 @@ +import paddle +import paddle.nn.functional as F +from ppdet.modeling.losses.clrnet_line_iou_loss import line_iou + + +def distance_cost(predictions, targets, img_w): + """ + repeat predictions and targets to generate all combinations + use the abs distance as the new distance cost + """ + num_priors = predictions.shape[0] + num_targets = targets.shape[0] + predictions = paddle.repeat_interleave( + predictions, num_targets, axis=0)[..., 6:] + targets = paddle.concat(x=num_priors * [targets])[..., 6:] + invalid_masks = (targets < 0) | (targets >= img_w) + lengths = (~invalid_masks).sum(axis=1) + distances = paddle.abs(x=targets - predictions) + distances[invalid_masks] = 0.0 + distances = distances.sum(axis=1) / (lengths.cast("float32") + 1e-09) + distances = distances.reshape([num_priors, num_targets]) + return distances + + +def focal_cost(cls_pred, gt_labels, alpha=0.25, gamma=2, eps=1e-12): + """ + Args: + cls_pred (Tensor): Predicted classification logits, shape + [num_query, num_class]. + gt_labels (Tensor): Label of `gt_bboxes`, shape (num_gt,). + + Returns: + torch.Tensor: cls_cost value + """ + cls_pred = F.sigmoid(cls_pred) + neg_cost = -(1 - cls_pred + eps).log() * (1 - alpha) * cls_pred.pow(gamma) + pos_cost = -(cls_pred + eps).log() * alpha * (1 - cls_pred).pow(gamma) + cls_cost = pos_cost.index_select( + gt_labels, axis=1) - neg_cost.index_select( + gt_labels, axis=1) + return cls_cost + + +def dynamic_k_assign(cost, pair_wise_ious): + """ + Assign grouth truths with priors dynamically. + + Args: + cost: the assign cost. + pair_wise_ious: iou of grouth truth and priors. + + Returns: + prior_idx: the index of assigned prior. + gt_idx: the corresponding ground truth index. + """ + matching_matrix = paddle.zeros_like(cost) + ious_matrix = pair_wise_ious + ious_matrix[ious_matrix < 0] = 0.0 + n_candidate_k = 4 + topk_ious, _ = paddle.topk(ious_matrix, n_candidate_k, axis=0) + dynamic_ks = paddle.clip(x=topk_ious.sum(0).cast("int32"), min=1) + num_gt = cost.shape[1] + + for gt_idx in range(num_gt): + _, pos_idx = paddle.topk( + x=cost[:, gt_idx], k=dynamic_ks[gt_idx].item(), largest=False) + matching_matrix[pos_idx, gt_idx] = 1.0 + del topk_ious, dynamic_ks, pos_idx + matched_gt = matching_matrix.sum(axis=1) + + if (matched_gt > 1).sum() > 0: + matched_gt_indices = paddle.nonzero(matched_gt > 1)[:, 0] + cost_argmin = paddle.argmin( + cost.index_select(matched_gt_indices), axis=1) + matching_matrix[matched_gt_indices][0] *= 0.0 + matching_matrix[matched_gt_indices, cost_argmin] = 1.0 + + prior_idx = matching_matrix.sum(axis=1).nonzero() + gt_idx = matching_matrix[prior_idx].argmax(axis=-1) + return prior_idx.flatten(), gt_idx.flatten() + + +def cdist_paddle(x1, x2, p=2): + assert x1.shape[1] == x2.shape[1] + B, M = x1.shape + # if p == np.inf: + # dist = np.max(np.abs(x1[:, np.newaxis, :] - x2[np.newaxis, :, :]), axis=-1) + if p == 1: + dist = paddle.sum( + paddle.abs(x1.unsqueeze(axis=1) - x2.unsqueeze(axis=0)), axis=-1) + else: + dist = paddle.pow(paddle.sum(paddle.pow( + paddle.abs(x1.unsqueeze(axis=1) - x2.unsqueeze(axis=0)), p), + axis=-1), + 1 / p) + return dist + + +def assign(predictions, + targets, + img_w, + img_h, + distance_cost_weight=3.0, + cls_cost_weight=1.0): + """ + computes dynamicly matching based on the cost, including cls cost and lane similarity cost + Args: + predictions (Tensor): predictions predicted by each stage, shape: (num_priors, 78) + targets (Tensor): lane targets, shape: (num_targets, 78) + return: + matched_row_inds (Tensor): matched predictions, shape: (num_targets) + matched_col_inds (Tensor): matched targets, shape: (num_targets) + """ + predictions = predictions.detach().clone() + predictions[:, 3] *= img_w - 1 + predictions[:, 6:] *= img_w - 1 + + targets = targets.detach().clone() + distances_score = distance_cost(predictions, targets, img_w) + distances_score = 1 - distances_score / paddle.max(x=distances_score) + 0.01 + + cls_score = focal_cost(predictions[:, :2], targets[:, 1].cast('int64')) + + num_priors = predictions.shape[0] + num_targets = targets.shape[0] + target_start_xys = targets[:, 2:4] + target_start_xys[..., 0] *= (img_h - 1) + prediction_start_xys = predictions[:, 2:4] + prediction_start_xys[..., 0] *= (img_h - 1) + start_xys_score = cdist_paddle( + prediction_start_xys, target_start_xys, + p=2).reshape([num_priors, num_targets]) + + start_xys_score = 1 - start_xys_score / paddle.max(x=start_xys_score) + 0.01 + + target_thetas = targets[:, 4].unsqueeze(axis=-1) + theta_score = cdist_paddle( + predictions[:, 4].unsqueeze(axis=-1), target_thetas, + p=1).reshape([num_priors, num_targets]) * 180 + theta_score = 1 - theta_score / paddle.max(x=theta_score) + 0.01 + + cost = -(distances_score * start_xys_score * theta_score + )**2 * distance_cost_weight + cls_score * cls_cost_weight + iou = line_iou(predictions[..., 6:], targets[..., 6:], img_w, aligned=False) + + matched_row_inds, matched_col_inds = dynamic_k_assign(cost, iou) + return matched_row_inds, matched_col_inds diff --git a/ppdet/modeling/backbones/__init__.py b/ppdet/modeling/backbones/__init__.py index e61ff7111..bc000c72d 100644 --- a/ppdet/modeling/backbones/__init__.py +++ b/ppdet/modeling/backbones/__init__.py @@ -38,6 +38,7 @@ from . import trans_encoder from . import focalnet from . import vit_mae from . import hgnet_v2 +from . import clrnet_resnet from .vgg import * from .resnet import * @@ -66,3 +67,4 @@ from .focalnet import * from .vitpose import * from .vit_mae import * from .hgnet_v2 import * +from .clrnet_resnet import * diff --git a/ppdet/modeling/backbones/clrnet_resnet.py b/ppdet/modeling/backbones/clrnet_resnet.py new file mode 100644 index 000000000..00758df55 --- /dev/null +++ b/ppdet/modeling/backbones/clrnet_resnet.py @@ -0,0 +1,697 @@ +# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import division +from __future__ import print_function + +import paddle +import paddle.nn as nn + +from paddle.utils.download import get_weights_path_from_url +from ppdet.core.workspace import register, serializable +from ..shape_spec import ShapeSpec + +__all__ = ['CLRResNet'] + +model_urls = { + 'resnet18': + 'https://x2paddle.bj.bcebos.com/vision/models/resnet18-pt.pdparams', + 'resnet34': + 'https://x2paddle.bj.bcebos.com/vision/models/resnet34-pt.pdparams', + 'resnet50': + 'https://x2paddle.bj.bcebos.com/vision/models/resnet50-pt.pdparams', + 'resnet101': + 'https://x2paddle.bj.bcebos.com/vision/models/resnet101-pt.pdparams', + 'resnet152': + 'https://x2paddle.bj.bcebos.com/vision/models/resnet152-pt.pdparams', + 'resnext50_32x4d': + 'https://x2paddle.bj.bcebos.com/vision/models/resnext50_32x4d-pt.pdparams', + 'resnext101_32x8d': + 'https://x2paddle.bj.bcebos.com/vision/models/resnext101_32x8d-pt.pdparams', + 'wide_resnet50_2': + 'https://x2paddle.bj.bcebos.com/vision/models/wide_resnet50_2-pt.pdparams', + 'wide_resnet101_2': + 'https://x2paddle.bj.bcebos.com/vision/models/wide_resnet101_2-pt.pdparams', +} + + +class BasicBlock(nn.Layer): + expansion = 1 + + def __init__(self, + inplanes, + planes, + stride=1, + downsample=None, + groups=1, + base_width=64, + dilation=1, + norm_layer=None): + super(BasicBlock, self).__init__() + if norm_layer is None: + norm_layer = nn.BatchNorm2D + + if dilation > 1: + raise NotImplementedError( + "Dilation > 1 not supported in BasicBlock") + + self.conv1 = nn.Conv2D( + inplanes, planes, 3, padding=1, stride=stride, bias_attr=False) + self.bn1 = norm_layer(planes) + self.relu = nn.ReLU() + self.conv2 = nn.Conv2D(planes, planes, 3, padding=1, bias_attr=False) + self.bn2 = norm_layer(planes) + self.downsample = downsample + self.stride = stride + + def forward(self, x): + identity = x + + out = self.conv1(x) + out = self.bn1(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.bn2(out) + + if self.downsample is not None: + identity = self.downsample(x) + + out += identity + out = self.relu(out) + + return out + + +class BottleneckBlock(nn.Layer): + + expansion = 4 + + def __init__(self, + inplanes, + planes, + stride=1, + downsample=None, + groups=1, + base_width=64, + dilation=1, + norm_layer=None): + super(BottleneckBlock, self).__init__() + if norm_layer is None: + norm_layer = nn.BatchNorm2D + width = int(planes * (base_width / 64.)) * groups + + self.conv1 = nn.Conv2D(inplanes, width, 1, bias_attr=False) + self.bn1 = norm_layer(width) + + self.conv2 = nn.Conv2D( + width, + width, + 3, + padding=dilation, + stride=stride, + groups=groups, + dilation=dilation, + bias_attr=False) + self.bn2 = norm_layer(width) + + self.conv3 = nn.Conv2D( + width, planes * self.expansion, 1, bias_attr=False) + self.bn3 = norm_layer(planes * self.expansion) + self.relu = nn.ReLU() + self.downsample = downsample + self.stride = stride + + def forward(self, x): + identity = x + + out = self.conv1(x) + out = self.bn1(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.bn2(out) + out = self.relu(out) + + out = self.conv3(out) + out = self.bn3(out) + + if self.downsample is not None: + identity = self.downsample(x) + + out += identity + out = self.relu(out) + + return out + + +class ResNet(nn.Layer): + """ResNet model from + `"Deep Residual Learning for Image Recognition" `_. + Args: + Block (BasicBlock|BottleneckBlock): Block module of model. + depth (int, optional): Layers of ResNet, Default: 50. + width (int, optional): Base width per convolution group for each convolution block, Default: 64. + num_classes (int, optional): Output dim of last fc layer. If num_classes <= 0, last fc layer + will not be defined. Default: 1000. + with_pool (bool, optional): Use pool before the last fc layer or not. Default: True. + groups (int, optional): Number of groups for each convolution block, Default: 1. + Returns: + :ref:`api_paddle_nn_Layer`. An instance of ResNet model. + Examples: + .. code-block:: python + import paddle + from paddle.vision.models import ResNet + from paddle.vision.models.resnet import BottleneckBlock, BasicBlock + # build ResNet with 18 layers + resnet18 = ResNet(BasicBlock, 18) + # build ResNet with 50 layers + resnet50 = ResNet(BottleneckBlock, 50) + # build Wide ResNet model + wide_resnet50_2 = ResNet(BottleneckBlock, 50, width=64*2) + # build ResNeXt model + resnext50_32x4d = ResNet(BottleneckBlock, 50, width=4, groups=32) + x = paddle.rand([1, 3, 224, 224]) + out = resnet18(x) + print(out.shape) + # [1, 1000] + """ + + def __init__(self, block, depth=50, width=64, with_pool=True, groups=1): + super(ResNet, self).__init__() + layer_cfg = { + 18: [2, 2, 2, 2], + 34: [3, 4, 6, 3], + 50: [3, 4, 6, 3], + 101: [3, 4, 23, 3], + 152: [3, 8, 36, 3] + } + + layers = layer_cfg[depth] + self.groups = groups + self.base_width = width + self.with_pool = with_pool + self._norm_layer = nn.BatchNorm2D + + self.inplanes = 64 + self.dilation = 1 + + self.conv1 = nn.Conv2D( + 3, + self.inplanes, + kernel_size=7, + stride=2, + padding=3, + bias_attr=False) + self.bn1 = self._norm_layer(self.inplanes) + self.relu = nn.ReLU() + self.maxpool = nn.MaxPool2D(kernel_size=3, stride=2, padding=1) + self.layer1 = self._make_layer(block, 64, layers[0]) + self.layer2 = self._make_layer(block, 128, layers[1], stride=2) + self.layer3 = self._make_layer(block, 256, layers[2], stride=2) + self.layer4 = self._make_layer(block, 512, layers[3], stride=2) + if with_pool: + self.avgpool = nn.AdaptiveAvgPool2D((1, 1)) + + ch_out_list = [64, 128, 256, 512] + block = BottleneckBlock if depth >= 50 else BasicBlock + + self._out_channels = [block.expansion * v for v in ch_out_list] + self._out_strides = [4, 8, 16, 32] + self.return_idx = [0, 1, 2, 3] + + def _make_layer(self, block, planes, blocks, stride=1, dilate=False): + norm_layer = self._norm_layer + downsample = None + previous_dilation = self.dilation + if dilate: + self.dilation *= stride + stride = 1 + if stride != 1 or self.inplanes != planes * block.expansion: + downsample = nn.Sequential( + nn.Conv2D( + self.inplanes, + planes * block.expansion, + 1, + stride=stride, + bias_attr=False), + norm_layer(planes * block.expansion), ) + + layers = [] + layers.append( + block(self.inplanes, planes, stride, downsample, self.groups, + self.base_width, previous_dilation, norm_layer)) + self.inplanes = planes * block.expansion + for _ in range(1, blocks): + layers.append( + block( + self.inplanes, + planes, + groups=self.groups, + base_width=self.base_width, + norm_layer=norm_layer)) + + return nn.Sequential(*layers) + + @property + def out_shape(self): + return [ + ShapeSpec( + channels=self._out_channels[i], stride=self._out_strides[i]) + for i in self.return_idx + ] + + def forward(self, x): + x = self.conv1(x) + x = self.bn1(x) + x = self.relu(x) + x = self.maxpool(x) + + out_layers = [] + x = self.layer1(x) + out_layers.append(x) + x = self.layer2(x) + out_layers.append(x) + x = self.layer3(x) + out_layers.append(x) + x = self.layer4(x) + out_layers.append(x) + + if self.with_pool: + x = self.avgpool(x) + + return out_layers + + +@register +@serializable +class CLRResNet(nn.Layer): + def __init__(self, + resnet='resnet18', + pretrained=True, + out_conv=False, + fea_stride=8, + out_channel=128, + in_channels=[64, 128, 256, 512], + cfg=None): + super(CLRResNet, self).__init__() + self.cfg = cfg + self.in_channels = in_channels + + self.model = eval(resnet)(pretrained=pretrained) + self.out = None + if out_conv: + out_channel = 512 + for chan in reversed(self.in_channels): + if chan < 0: continue + out_channel = chan + break + self.out = nn.Conv2D( + out_channel * self.model.expansion, + cfg.featuremap_out_channel, + kernel_size=1, + bias_attr=False) + + @property + def out_shape(self): + return self.model.out_shape + + def forward(self, x): + x = self.model(x) + if self.out: + x[-1] = self.out(x[-1]) + return x + + +def _resnet(arch, Block, depth, pretrained, **kwargs): + model = ResNet(Block, depth, **kwargs) + if pretrained: + assert arch in model_urls, "{} model do not have a pretrained model now, you should set pretrained=False".format( + arch) + weight_path = get_weights_path_from_url(model_urls[arch]) + + param = paddle.load(weight_path) + model.set_dict(param) + + return model + + +def resnet18(pretrained=False, **kwargs): + """ResNet 18-layer model from + `"Deep Residual Learning for Image Recognition" `_. + Args: + pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained + on ImageNet. Default: False. + **kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`ResNet `. + Returns: + :ref:`api_paddle_nn_Layer`. An instance of ResNet 18-layer model. + Examples: + .. code-block:: python + import paddle + from paddle.vision.models import resnet18 + # build model + model = resnet18() + # build model and load imagenet pretrained weight + # model = resnet18(pretrained=True) + x = paddle.rand([1, 3, 224, 224]) + out = model(x) + print(out.shape) + # [1, 1000] + """ + return _resnet('resnet18', BasicBlock, 18, pretrained, **kwargs) + + +def resnet34(pretrained=False, **kwargs): + """ResNet 34-layer model from + `"Deep Residual Learning for Image Recognition" `_. + Args: + pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained + on ImageNet. Default: False. + **kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`ResNet `. + Returns: + :ref:`api_paddle_nn_Layer`. An instance of ResNet 34-layer model. + Examples: + .. code-block:: python + import paddle + from paddle.vision.models import resnet34 + # build model + model = resnet34() + # build model and load imagenet pretrained weight + # model = resnet34(pretrained=True) + x = paddle.rand([1, 3, 224, 224]) + out = model(x) + print(out.shape) + # [1, 1000] + """ + return _resnet('resnet34', BasicBlock, 34, pretrained, **kwargs) + + +def resnet50(pretrained=False, **kwargs): + """ResNet 50-layer model from + `"Deep Residual Learning for Image Recognition" `_. + Args: + pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained + on ImageNet. Default: False. + **kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`ResNet `. + Returns: + :ref:`api_paddle_nn_Layer`. An instance of ResNet 50-layer model. + Examples: + .. code-block:: python + import paddle + from paddle.vision.models import resnet50 + # build model + model = resnet50() + # build model and load imagenet pretrained weight + # model = resnet50(pretrained=True) + x = paddle.rand([1, 3, 224, 224]) + out = model(x) + print(out.shape) + # [1, 1000] + """ + return _resnet('resnet50', BottleneckBlock, 50, pretrained, **kwargs) + + +def resnet101(pretrained=False, **kwargs): + """ResNet 101-layer model from + `"Deep Residual Learning for Image Recognition" `_. + Args: + pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained + on ImageNet. Default: False. + **kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`ResNet `. + Returns: + :ref:`api_paddle_nn_Layer`. An instance of ResNet 101-layer. + Examples: + .. code-block:: python + import paddle + from paddle.vision.models import resnet101 + # build model + model = resnet101() + # build model and load imagenet pretrained weight + # model = resnet101(pretrained=True) + x = paddle.rand([1, 3, 224, 224]) + out = model(x) + print(out.shape) + # [1, 1000] + """ + return _resnet('resnet101', BottleneckBlock, 101, pretrained, **kwargs) + + +def resnet152(pretrained=False, **kwargs): + """ResNet 152-layer model from + `"Deep Residual Learning for Image Recognition" `_. + Args: + pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained + on ImageNet. Default: False. + **kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`ResNet `. + Returns: + :ref:`api_paddle_nn_Layer`. An instance of ResNet 152-layer model. + Examples: + .. code-block:: python + import paddle + from paddle.vision.models import resnet152 + # build model + model = resnet152() + # build model and load imagenet pretrained weight + # model = resnet152(pretrained=True) + x = paddle.rand([1, 3, 224, 224]) + out = model(x) + print(out.shape) + # [1, 1000] + """ + return _resnet('resnet152', BottleneckBlock, 152, pretrained, **kwargs) + + +def resnext50_32x4d(pretrained=False, **kwargs): + """ResNeXt-50 32x4d model from + `"Aggregated Residual Transformations for Deep Neural Networks" `_. + + Args: + pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained + on ImageNet. Default: False. + **kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`ResNet `. + Returns: + :ref:`api_paddle_nn_Layer`. An instance of ResNeXt-50 32x4d model. + Examples: + .. code-block:: python + import paddle + from paddle.vision.models import resnext50_32x4d + # build model + model = resnext50_32x4d() + # build model and load imagenet pretrained weight + # model = resnext50_32x4d(pretrained=True) + x = paddle.rand([1, 3, 224, 224]) + out = model(x) + print(out.shape) + # [1, 1000] + """ + kwargs['groups'] = 32 + kwargs['width'] = 4 + return _resnet('resnext50_32x4d', BottleneckBlock, 50, pretrained, **kwargs) + + +def resnext50_64x4d(pretrained=False, **kwargs): + """ResNeXt-50 64x4d model from + `"Aggregated Residual Transformations for Deep Neural Networks" `_. + + Args: + pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained + on ImageNet. Default: False. + **kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`ResNet `. + Returns: + :ref:`api_paddle_nn_Layer`. An instance of ResNeXt-50 64x4d model. + Examples: + .. code-block:: python + import paddle + from paddle.vision.models import resnext50_64x4d + # build model + model = resnext50_64x4d() + # build model and load imagenet pretrained weight + # model = resnext50_64x4d(pretrained=True) + x = paddle.rand([1, 3, 224, 224]) + out = model(x) + print(out.shape) + # [1, 1000] + """ + kwargs['groups'] = 64 + kwargs['width'] = 4 + return _resnet('resnext50_64x4d', BottleneckBlock, 50, pretrained, **kwargs) + + +def resnext101_32x4d(pretrained=False, **kwargs): + """ResNeXt-101 32x4d model from + `"Aggregated Residual Transformations for Deep Neural Networks" `_. + + Args: + pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained + on ImageNet. Default: False. + **kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`ResNet `. + Returns: + :ref:`api_paddle_nn_Layer`. An instance of ResNeXt-101 32x4d model. + Examples: + .. code-block:: python + import paddle + from paddle.vision.models import resnext101_32x4d + # build model + model = resnext101_32x4d() + # build model and load imagenet pretrained weight + # model = resnext101_32x4d(pretrained=True) + x = paddle.rand([1, 3, 224, 224]) + out = model(x) + print(out.shape) + # [1, 1000] + """ + kwargs['groups'] = 32 + kwargs['width'] = 4 + return _resnet('resnext101_32x4d', BottleneckBlock, 101, pretrained, + **kwargs) + + +def resnext101_64x4d(pretrained=False, **kwargs): + """ResNeXt-101 64x4d model from + `"Aggregated Residual Transformations for Deep Neural Networks" `_. + + Args: + pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained + on ImageNet. Default: False. + **kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`ResNet `. + Returns: + :ref:`api_paddle_nn_Layer`. An instance of ResNeXt-101 64x4d model. + Examples: + .. code-block:: python + import paddle + from paddle.vision.models import resnext101_64x4d + # build model + model = resnext101_64x4d() + # build model and load imagenet pretrained weight + # model = resnext101_64x4d(pretrained=True) + x = paddle.rand([1, 3, 224, 224]) + out = model(x) + print(out.shape) + # [1, 1000] + """ + kwargs['groups'] = 64 + kwargs['width'] = 4 + return _resnet('resnext101_64x4d', BottleneckBlock, 101, pretrained, + **kwargs) + + +def resnext152_32x4d(pretrained=False, **kwargs): + """ResNeXt-152 32x4d model from + `"Aggregated Residual Transformations for Deep Neural Networks" `_. + + Args: + pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained + on ImageNet. Default: False. + **kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`ResNet `. + Returns: + :ref:`api_paddle_nn_Layer`. An instance of ResNeXt-152 32x4d model. + Examples: + .. code-block:: python + import paddle + from paddle.vision.models import resnext152_32x4d + # build model + model = resnext152_32x4d() + # build model and load imagenet pretrained weight + # model = resnext152_32x4d(pretrained=True) + x = paddle.rand([1, 3, 224, 224]) + out = model(x) + print(out.shape) + # [1, 1000] + """ + kwargs['groups'] = 32 + kwargs['width'] = 4 + return _resnet('resnext152_32x4d', BottleneckBlock, 152, pretrained, + **kwargs) + + +def resnext152_64x4d(pretrained=False, **kwargs): + """ResNeXt-152 64x4d model from + `"Aggregated Residual Transformations for Deep Neural Networks" `_. + + Args: + pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained + on ImageNet. Default: False. + **kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`ResNet `. + Returns: + :ref:`api_paddle_nn_Layer`. An instance of ResNeXt-152 64x4d model. + Examples: + .. code-block:: python + import paddle + from paddle.vision.models import resnext152_64x4d + # build model + model = resnext152_64x4d() + # build model and load imagenet pretrained weight + # model = resnext152_64x4d(pretrained=True) + x = paddle.rand([1, 3, 224, 224]) + out = model(x) + print(out.shape) + # [1, 1000] + """ + kwargs['groups'] = 64 + kwargs['width'] = 4 + return _resnet('resnext152_64x4d', BottleneckBlock, 152, pretrained, + **kwargs) + + +def wide_resnet50_2(pretrained=False, **kwargs): + """Wide ResNet-50-2 model from + `"Wide Residual Networks" `_. + Args: + pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained + on ImageNet. Default: False. + **kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`ResNet `. + Returns: + :ref:`api_paddle_nn_Layer`. An instance of Wide ResNet-50-2 model. + Examples: + .. code-block:: python + import paddle + from paddle.vision.models import wide_resnet50_2 + # build model + model = wide_resnet50_2() + # build model and load imagenet pretrained weight + # model = wide_resnet50_2(pretrained=True) + x = paddle.rand([1, 3, 224, 224]) + out = model(x) + print(out.shape) + # [1, 1000] + """ + kwargs['width'] = 64 * 2 + return _resnet('wide_resnet50_2', BottleneckBlock, 50, pretrained, **kwargs) + + +def wide_resnet101_2(pretrained=False, **kwargs): + """Wide ResNet-101-2 model from + `"Wide Residual Networks" `_. + Args: + pretrained (bool, optional): Whether to load pre-trained weights. If True, returns a model pre-trained + on ImageNet. Default: False. + **kwargs (optional): Additional keyword arguments. For details, please refer to :ref:`ResNet `. + Returns: + :ref:`api_paddle_nn_Layer`. An instance of Wide ResNet-101-2 model. + Examples: + .. code-block:: python + import paddle + from paddle.vision.models import wide_resnet101_2 + # build model + model = wide_resnet101_2() + # build model and load imagenet pretrained weight + # model = wide_resnet101_2(pretrained=True) + x = paddle.rand([1, 3, 224, 224]) + out = model(x) + print(out.shape) + # [1, 1000] + """ + kwargs['width'] = 64 * 2 + return _resnet('wide_resnet101_2', BottleneckBlock, 101, pretrained, + **kwargs) diff --git a/ppdet/modeling/clrnet_utils.py b/ppdet/modeling/clrnet_utils.py new file mode 100644 index 000000000..24ece5c2e --- /dev/null +++ b/ppdet/modeling/clrnet_utils.py @@ -0,0 +1,309 @@ +import paddle +import paddle.nn as nn +import paddle.nn.functional as F +from ppdet.modeling.initializer import constant_ +from paddle.nn.initializer import KaimingNormal + + +class ConvModule(nn.Layer): + def __init__(self, + in_channels, + out_channels, + kernel_size=1, + stride=1, + padding=0, + dilation=1, + groups=1, + bias=False, + norm_type='bn', + wtih_act=True): + super(ConvModule, self).__init__() + assert norm_type in ['bn', 'sync_bn', 'gn', None] + self.with_norm = norm_type is not None + self.wtih_act = wtih_act + self.conv = nn.Conv2D( + in_channels=in_channels, + out_channels=out_channels, + kernel_size=kernel_size, + stride=stride, + padding=padding, + dilation=dilation, + groups=groups, + bias_attr=bias, + weight_attr=KaimingNormal()) + if self.with_norm: + if norm_type == 'bn': + self.bn = nn.BatchNorm2D(out_channels) + elif norm_type == 'gn': + self.bn = nn.GroupNorm(out_channels, out_channels) + + if self.wtih_act: + self.act = nn.ReLU() + + def forward(self, inputs): + x = self.conv(inputs) + if self.with_norm: + x = self.bn(x) + if self.wtih_act: + x = self.act(x) + return x + + +def LinearModule(hidden_dim): + return nn.LayerList( + [nn.Linear( + hidden_dim, hidden_dim, bias_attr=True), nn.ReLU()]) + + +class FeatureResize(nn.Layer): + def __init__(self, size=(10, 25)): + super(FeatureResize, self).__init__() + self.size = size + + def forward(self, x): + x = F.interpolate(x, self.size) + return x.flatten(2) + + +class ROIGather(nn.Layer): + ''' + ROIGather module for gather global information + Args: + in_channels: prior feature channels + num_priors: prior numbers we predefined + sample_points: the number of sampled points when we extract feature from line + fc_hidden_dim: the fc output channel + refine_layers: the total number of layers to build refine + ''' + + def __init__(self, + in_channels, + num_priors, + sample_points, + fc_hidden_dim, + refine_layers, + mid_channels=48): + super(ROIGather, self).__init__() + self.in_channels = in_channels + self.num_priors = num_priors + self.f_key = ConvModule( + in_channels=self.in_channels, + out_channels=self.in_channels, + kernel_size=1, + stride=1, + padding=0, + norm_type='bn') + + self.f_query = nn.Sequential( + nn.Conv1D( + in_channels=num_priors, + out_channels=num_priors, + kernel_size=1, + stride=1, + padding=0, + groups=num_priors), + nn.ReLU(), ) + self.f_value = nn.Conv2D( + in_channels=self.in_channels, + out_channels=self.in_channels, + kernel_size=1, + stride=1, + padding=0) + self.W = nn.Conv1D( + in_channels=num_priors, + out_channels=num_priors, + kernel_size=1, + stride=1, + padding=0, + groups=num_priors) + + self.resize = FeatureResize() + constant_(self.W.weight, 0) + constant_(self.W.bias, 0) + + self.convs = nn.LayerList() + self.catconv = nn.LayerList() + for i in range(refine_layers): + self.convs.append( + ConvModule( + in_channels, + mid_channels, (9, 1), + padding=(4, 0), + bias=False, + norm_type='bn')) + + self.catconv.append( + ConvModule( + mid_channels * (i + 1), + in_channels, (9, 1), + padding=(4, 0), + bias=False, + norm_type='bn')) + + self.fc = nn.Linear( + sample_points * fc_hidden_dim, fc_hidden_dim, bias_attr=True) + + self.fc_norm = nn.LayerNorm(fc_hidden_dim) + + def roi_fea(self, x, layer_index): + feats = [] + for i, feature in enumerate(x): + feat_trans = self.convs[i](feature) + feats.append(feat_trans) + cat_feat = paddle.concat(feats, axis=1) + cat_feat = self.catconv[layer_index](cat_feat) + return cat_feat + + def forward(self, roi_features, x, layer_index): + ''' + Args: + roi_features: prior feature, shape: (Batch * num_priors, prior_feat_channel, sample_point, 1) + x: feature map + layer_index: currently on which layer to refine + Return: + roi: prior features with gathered global information, shape: (Batch, num_priors, fc_hidden_dim) + ''' + + roi = self.roi_fea(roi_features, layer_index) + # return roi + # print(roi.shape) + # return roi + bs = x.shape[0] + # print(bs) + #roi = roi.contiguous().view(bs * self.num_priors, -1) + roi = roi.reshape([bs * self.num_priors, -1]) + # roi = paddle.randn([192,2304]) + # return roi + # print(roi) + # print(self.fc) + # print(self.fc.weight) + roi = self.fc(roi) + roi = F.relu(self.fc_norm(roi)) + # return roi + #roi = roi.view(bs, self.num_priors, -1) + roi = roi.reshape([bs, self.num_priors, -1]) + query = roi + + value = self.resize(self.f_value(x)) # (B, C, N) global feature + query = self.f_query( + query) # (B, N, 1) sample context feature from prior roi + key = self.f_key(x) + value = value.transpose(perm=[0, 2, 1]) + key = self.resize(key) # (B, C, N) global feature + sim_map = paddle.matmul(query, key) + sim_map = (self.in_channels**-.5) * sim_map + sim_map = F.softmax(sim_map, axis=-1) + + context = paddle.matmul(sim_map, value) + context = self.W(context) + + roi = roi + F.dropout(context, p=0.1, training=self.training) + + return roi + + +class SegDecoder(nn.Layer): + ''' + Optionaly seg decoder + ''' + + def __init__(self, + image_height, + image_width, + num_class, + prior_feat_channels=64, + refine_layers=3): + super().__init__() + self.dropout = nn.Dropout2D(0.1) + self.conv = nn.Conv2D(prior_feat_channels * refine_layers, num_class, 1) + self.image_height = image_height + self.image_width = image_width + + def forward(self, x): + x = self.dropout(x) + x = self.conv(x) + x = F.interpolate( + x, + size=[self.image_height, self.image_width], + mode='bilinear', + align_corners=False) + return x + + +import paddle.nn as nn + + +def accuracy(pred, target, topk=1, thresh=None): + """Calculate accuracy according to the prediction and target. + + Args: + pred (torch.Tensor): The model prediction, shape (N, num_class) + target (torch.Tensor): The target of each prediction, shape (N, ) + topk (int | tuple[int], optional): If the predictions in ``topk`` + matches the target, the predictions will be regarded as + correct ones. Defaults to 1. + thresh (float, optional): If not None, predictions with scores under + this threshold are considered incorrect. Default to None. + + Returns: + float | tuple[float]: If the input ``topk`` is a single integer, + the function will return a single float as accuracy. If + ``topk`` is a tuple containing multiple integers, the + function will return a tuple containing accuracies of + each ``topk`` number. + """ + assert isinstance(topk, (int, tuple)) + if isinstance(topk, int): + topk = (topk, ) + return_single = True + else: + return_single = False + + maxk = max(topk) + if pred.shape[0] == 0: + accu = [pred.new_tensor(0.) for i in range(len(topk))] + return accu[0] if return_single else accu + assert pred.ndim == 2 and target.ndim == 1 + assert pred.shape[0] == target.shape[0] + assert maxk <= pred.shape[1], \ + f'maxk {maxk} exceeds pred dimension {pred.shape[1]}' + pred_value, pred_label = pred.topk(maxk, axis=1) + pred_label = pred_label.t() # transpose to shape (maxk, N) + correct = pred_label.equal(target.reshape([1, -1]).expand_as(pred_label)) + if thresh is not None: + # Only prediction values larger than thresh are counted as correct + correct = correct & (pred_value > thresh).t() + res = [] + for k in topk: + correct_k = correct[:k].reshape([-1]).cast("float32").sum(0, + keepdim=True) + correct_k = correct_k * (100.0 / pred.shape[0]) + res.append(correct_k) + return res[0] if return_single else res + + +class Accuracy(nn.Layer): + def __init__(self, topk=(1, ), thresh=None): + """Module to calculate the accuracy. + + Args: + topk (tuple, optional): The criterion used to calculate the + accuracy. Defaults to (1,). + thresh (float, optional): If not None, predictions with scores + under this threshold are considered incorrect. Default to None. + """ + super().__init__() + self.topk = topk + self.thresh = thresh + + def forward(self, pred, target): + """Forward function to calculate accuracy. + + Args: + pred (torch.Tensor): Prediction of models. + target (torch.Tensor): Target for each prediction. + + Returns: + tuple[float]: The accuracies under different topk criterions. + """ + return accuracy(pred, target, self.topk, self.thresh) diff --git a/ppdet/modeling/heads/__init__.py b/ppdet/modeling/heads/__init__.py index 44a9fa85d..0d126c08f 100644 --- a/ppdet/modeling/heads/__init__.py +++ b/ppdet/modeling/heads/__init__.py @@ -40,6 +40,7 @@ from . import ppyoloe_contrast_head from . import centertrack_head from . import sparse_roi_head from . import vitpose_head +from . import clrnet_head from .bbox_head import * from .mask_head import * @@ -69,4 +70,5 @@ from .ppyoloe_contrast_head import * from .centertrack_head import * from .sparse_roi_head import * from .petr_head import * -from .vitpose_head import * \ No newline at end of file +from .vitpose_head import * +from .clrnet_head import * \ No newline at end of file diff --git a/ppdet/modeling/heads/clrnet_head.py b/ppdet/modeling/heads/clrnet_head.py new file mode 100644 index 000000000..14760b9ef --- /dev/null +++ b/ppdet/modeling/heads/clrnet_head.py @@ -0,0 +1,399 @@ +import math +import paddle +import numpy as np +import paddle.nn as nn +import paddle.nn.functional as F +from ppdet.core.workspace import register + +from ppdet.modeling.initializer import normal_ +from ppdet.modeling.lane_utils import Lane +from ppdet.modeling.losses import line_iou +from ppdet.modeling.clrnet_utils import ROIGather, LinearModule, SegDecoder + +__all__ = ['CLRHead'] + + +@register +class CLRHead(nn.Layer): + __inject__ = ['loss'] + __shared__ = [ + 'img_w', 'img_h', 'ori_img_h', 'num_classes', 'cut_height', + 'num_points', "max_lanes" + ] + + def __init__(self, + num_points=72, + prior_feat_channels=64, + fc_hidden_dim=64, + num_priors=192, + img_w=800, + img_h=320, + ori_img_h=590, + cut_height=270, + num_classes=5, + num_fc=2, + refine_layers=3, + sample_points=36, + conf_threshold=0.4, + nms_thres=0.5, + max_lanes=4, + loss='CLRNetLoss'): + super(CLRHead, self).__init__() + self.img_w = img_w + self.img_h = img_h + self.n_strips = num_points - 1 + self.n_offsets = num_points + self.num_priors = num_priors + self.sample_points = sample_points + self.refine_layers = refine_layers + self.num_classes = num_classes + self.fc_hidden_dim = fc_hidden_dim + self.ori_img_h = ori_img_h + self.cut_height = cut_height + self.conf_threshold = conf_threshold + self.nms_thres = nms_thres + self.max_lanes = max_lanes + self.prior_feat_channels = prior_feat_channels + self.loss = loss + self.register_buffer( + name='sample_x_indexs', + tensor=(paddle.linspace( + start=0, stop=1, num=self.sample_points, + dtype=paddle.float32) * self.n_strips).astype(dtype='int64')) + self.register_buffer( + name='prior_feat_ys', + tensor=paddle.flip( + x=(1 - self.sample_x_indexs.astype('float32') / self.n_strips), + axis=[-1])) + self.register_buffer( + name='prior_ys', + tensor=paddle.linspace( + start=1, stop=0, num=self.n_offsets).astype('float32')) + self.prior_feat_channels = prior_feat_channels + self._init_prior_embeddings() + init_priors, priors_on_featmap = self.generate_priors_from_embeddings() + self.register_buffer(name='priors', tensor=init_priors) + self.register_buffer(name='priors_on_featmap', tensor=priors_on_featmap) + self.seg_decoder = SegDecoder(self.img_h, self.img_w, self.num_classes, + self.prior_feat_channels, + self.refine_layers) + reg_modules = list() + cls_modules = list() + for _ in range(num_fc): + reg_modules += [*LinearModule(self.fc_hidden_dim)] + cls_modules += [*LinearModule(self.fc_hidden_dim)] + self.reg_modules = nn.LayerList(sublayers=reg_modules) + self.cls_modules = nn.LayerList(sublayers=cls_modules) + self.roi_gather = ROIGather(self.prior_feat_channels, self.num_priors, + self.sample_points, self.fc_hidden_dim, + self.refine_layers) + self.reg_layers = nn.Linear( + in_features=self.fc_hidden_dim, + out_features=self.n_offsets + 1 + 2 + 1, + bias_attr=True) + self.cls_layers = nn.Linear( + in_features=self.fc_hidden_dim, out_features=2, bias_attr=True) + self.init_weights() + + def init_weights(self): + for m in self.cls_layers.parameters(): + normal_(m, mean=0.0, std=0.001) + for m in self.reg_layers.parameters(): + normal_(m, mean=0.0, std=0.001) + + def pool_prior_features(self, batch_features, num_priors, prior_xs): + """ + pool prior feature from feature map. + Args: + batch_features (Tensor): Input feature maps, shape: (B, C, H, W) + """ + batch_size = batch_features.shape[0] + prior_xs = prior_xs.reshape([batch_size, num_priors, -1, 1]) + + prior_ys = self.prior_feat_ys.tile(repeat_times=[ + batch_size * num_priors + ]).reshape([batch_size, num_priors, -1, 1]) + prior_xs = prior_xs * 2.0 - 1.0 + prior_ys = prior_ys * 2.0 - 1.0 + grid = paddle.concat(x=(prior_xs, prior_ys), axis=-1) + feature = F.grid_sample( + x=batch_features, grid=grid, + align_corners=True).transpose(perm=[0, 2, 1, 3]) + feature = feature.reshape([ + batch_size * num_priors, self.prior_feat_channels, + self.sample_points, 1 + ]) + return feature + + def generate_priors_from_embeddings(self): + predictions = self.prior_embeddings.weight + # 2 scores, 1 start_y, 1 start_x, 1 theta, 1 length, 72 coordinates, score[0] = negative prob, score[1] = positive prob + priors = paddle.zeros( + (self.num_priors, 2 + 2 + 2 + self.n_offsets), + dtype=predictions.dtype) + priors[:, 2:5] = predictions.clone() + priors[:, 6:] = ( + priors[:, 3].unsqueeze(1).clone().tile([1, self.n_offsets]) * + (self.img_w - 1) + + ((1 - self.prior_ys.tile([self.num_priors, 1]) - + priors[:, 2].unsqueeze(1).clone().tile([1, self.n_offsets])) * + self.img_h / paddle.tan(x=priors[:, 4].unsqueeze(1).clone().tile( + [1, self.n_offsets]) * math.pi + 1e-05))) / (self.img_w - 1) + priors_on_featmap = paddle.index_select( + priors, 6 + self.sample_x_indexs, axis=-1) + return priors, priors_on_featmap + + def _init_prior_embeddings(self): + self.prior_embeddings = nn.Embedding(self.num_priors, 3) + bottom_priors_nums = self.num_priors * 3 // 4 + left_priors_nums, _ = self.num_priors // 8, self.num_priors // 8 + strip_size = 0.5 / (left_priors_nums // 2 - 1) + bottom_strip_size = 1 / (bottom_priors_nums // 4 + 1) + + with paddle.no_grad(): + for i in range(left_priors_nums): + self.prior_embeddings.weight[i, 0] = i // 2 * strip_size + self.prior_embeddings.weight[i, 1] = 0.0 + self.prior_embeddings.weight[i, + 2] = 0.16 if i % 2 == 0 else 0.32 + + for i in range(left_priors_nums, + left_priors_nums + bottom_priors_nums): + self.prior_embeddings.weight[i, 0] = 0.0 + self.prior_embeddings.weight[i, 1] = ( + (i - left_priors_nums) // 4 + 1) * bottom_strip_size + self.prior_embeddings.weight[i, 2] = 0.2 * (i % 4 + 1) + + for i in range(left_priors_nums + bottom_priors_nums, + self.num_priors): + self.prior_embeddings.weight[i, 0] = ( + i - left_priors_nums - bottom_priors_nums) // 2 * strip_size + self.prior_embeddings.weight[i, 1] = 1.0 + self.prior_embeddings.weight[i, + 2] = 0.68 if i % 2 == 0 else 0.84 + + def forward(self, x, inputs=None): + """ + Take pyramid features as input to perform Cross Layer Refinement and finally output the prediction lanes. + Each feature is a 4D tensor. + Args: + x: input features (list[Tensor]) + Return: + prediction_list: each layer's prediction result + seg: segmentation result for auxiliary loss + """ + batch_features = list(x[len(x) - self.refine_layers:]) + batch_features.reverse() + batch_size = batch_features[-1].shape[0] + + if self.training: + self.priors, self.priors_on_featmap = self.generate_priors_from_embeddings( + ) + priors, priors_on_featmap = self.priors.tile( + [batch_size, 1, + 1]), self.priors_on_featmap.tile([batch_size, 1, 1]) + predictions_lists = [] + prior_features_stages = [] + + for stage in range(self.refine_layers): + num_priors = priors_on_featmap.shape[1] + prior_xs = paddle.flip(x=priors_on_featmap, axis=[2]) + batch_prior_features = self.pool_prior_features( + batch_features[stage], num_priors, prior_xs) + prior_features_stages.append(batch_prior_features) + + fc_features = self.roi_gather(prior_features_stages, + batch_features[stage], stage) + # return fc_features + fc_features = fc_features.reshape( + [num_priors, batch_size, -1]).reshape( + [batch_size * num_priors, self.fc_hidden_dim]) + cls_features = fc_features.clone() + reg_features = fc_features.clone() + + for cls_layer in self.cls_modules: + cls_features = cls_layer(cls_features) + + # return cls_features + for reg_layer in self.reg_modules: + reg_features = reg_layer(reg_features) + cls_logits = self.cls_layers(cls_features) + reg = self.reg_layers(reg_features) + + cls_logits = cls_logits.reshape( + [batch_size, -1, cls_logits.shape[1]]) + reg = reg.reshape([batch_size, -1, reg.shape[1]]) + predictions = priors.clone() + predictions[:, :, :2] = cls_logits + predictions[:, :, 2:5] += reg[:, :, :3] + predictions[:, :, 5] = reg[:, :, 3] + + def tran_tensor(t): + return t.unsqueeze(axis=2).clone().tile([1, 1, self.n_offsets]) + + predictions[..., 6:] = ( + tran_tensor(predictions[..., 3]) * (self.img_w - 1) + + ((1 - self.prior_ys.tile([batch_size, num_priors, 1]) - + tran_tensor(predictions[..., 2])) * self.img_h / paddle.tan( + tran_tensor(predictions[..., 4]) * math.pi + 1e-05))) / ( + self.img_w - 1) + + prediction_lines = predictions.clone() + predictions[..., 6:] += reg[..., 4:] + predictions_lists.append(predictions) + + if stage != self.refine_layers - 1: + priors = prediction_lines.detach().clone() + priors_on_featmap = priors.index_select( + 6 + self.sample_x_indexs, axis=-1) + + if self.training: + seg = None + seg_features = paddle.concat( + [ + F.interpolate( + feature, + size=[ + batch_features[-1].shape[2], + batch_features[-1].shape[3] + ], + mode='bilinear', + align_corners=False) for feature in batch_features + ], + axis=1) + + seg = self.seg_decoder(seg_features) + + output = {'predictions_lists': predictions_lists, 'seg': seg} + return self.loss(output, inputs) + return predictions_lists[-1] + + def predictions_to_pred(self, predictions): + """ + Convert predictions to internal Lane structure for evaluation. + """ + self.prior_ys = paddle.to_tensor(self.prior_ys) + self.prior_ys = self.prior_ys.astype('float64') + lanes = [] + for lane in predictions: + lane_xs = lane[6:].clone() + start = min( + max(0, int(round(lane[2].item() * self.n_strips))), + self.n_strips) + length = int(round(lane[5].item())) + end = start + length - 1 + end = min(end, len(self.prior_ys) - 1) + if start > 0: + mask = ((lane_xs[:start] >= 0.) & + (lane_xs[:start] <= 1.)).cpu().detach().numpy()[::-1] + mask = ~((mask.cumprod()[::-1]).astype(np.bool)) + lane_xs[:start][mask] = -2 + if end < len(self.prior_ys) - 1: + lane_xs[end + 1:] = -2 + + lane_ys = self.prior_ys[lane_xs >= 0].clone() + lane_xs = lane_xs[lane_xs >= 0] + lane_xs = lane_xs.flip(axis=0).astype('float64') + lane_ys = lane_ys.flip(axis=0) + + lane_ys = (lane_ys * + (self.ori_img_h - self.cut_height) + self.cut_height + ) / self.ori_img_h + if len(lane_xs) <= 1: + continue + points = paddle.stack( + x=(lane_xs.reshape([-1, 1]), lane_ys.reshape([-1, 1])), + axis=1).squeeze(axis=2) + lane = Lane( + points=points.cpu().numpy(), + metadata={ + 'start_x': lane[3], + 'start_y': lane[2], + 'conf': lane[1] + }) + lanes.append(lane) + return lanes + + def lane_nms(self, predictions, scores, nms_overlap_thresh, top_k): + """ + NMS for lane detection. + predictions: paddle.Tensor [num_lanes,conf,y,x,lenght,72offsets] [12,77] + scores: paddle.Tensor [num_lanes] + nms_overlap_thresh: float + top_k: int + """ + # sort by scores to get idx + idx = scores.argsort(descending=True) + keep = [] + + condidates = predictions.clone() + condidates = condidates.index_select(idx) + + while len(condidates) > 0: + keep.append(idx[0]) + if len(keep) >= top_k or len(condidates) == 1: + break + + ious = [] + for i in range(1, len(condidates)): + ious.append(1 - line_iou( + condidates[i].unsqueeze(0), + condidates[0].unsqueeze(0), + img_w=self.img_w, + length=15)) + ious = paddle.to_tensor(ious) + + mask = ious <= nms_overlap_thresh + id = paddle.where(mask == False)[0] + + if id.shape[0] == 0: + break + condidates = condidates[1:].index_select(id) + idx = idx[1:].index_select(id) + keep = paddle.stack(keep) + + return keep + + def get_lanes(self, output, as_lanes=True): + """ + Convert model output to lanes. + """ + softmax = nn.Softmax(axis=1) + decoded = [] + + for predictions in output: + threshold = self.conf_threshold + scores = softmax(predictions[:, :2])[:, 1] + keep_inds = scores >= threshold + predictions = predictions[keep_inds] + scores = scores[keep_inds] + + if predictions.shape[0] == 0: + decoded.append([]) + continue + nms_predictions = predictions.detach().clone() + nms_predictions = paddle.concat( + x=[nms_predictions[..., :4], nms_predictions[..., 5:]], axis=-1) + + nms_predictions[..., 4] = nms_predictions[..., 4] * self.n_strips + nms_predictions[..., 5:] = nms_predictions[..., 5:] * ( + self.img_w - 1) + + keep = self.lane_nms( + nms_predictions[..., 5:], + scores, + nms_overlap_thresh=self.nms_thres, + top_k=self.max_lanes) + + predictions = predictions.index_select(keep) + + if predictions.shape[0] == 0: + decoded.append([]) + continue + predictions[:, 5] = paddle.round(predictions[:, 5] * self.n_strips) + if as_lanes: + pred = self.predictions_to_pred(predictions) + else: + pred = predictions + decoded.append(pred) + return decoded diff --git a/ppdet/modeling/lane_utils.py b/ppdet/modeling/lane_utils.py new file mode 100644 index 000000000..e3fb45c66 --- /dev/null +++ b/ppdet/modeling/lane_utils.py @@ -0,0 +1,111 @@ +import os +import cv2 +import numpy as np +from scipy.interpolate import InterpolatedUnivariateSpline + + +class Lane: + def __init__(self, points=None, invalid_value=-2., metadata=None): + super(Lane, self).__init__() + self.curr_iter = 0 + self.points = points + self.invalid_value = invalid_value + self.function = InterpolatedUnivariateSpline( + points[:, 1], points[:, 0], k=min(3, len(points) - 1)) + self.min_y = points[:, 1].min() - 0.01 + self.max_y = points[:, 1].max() + 0.01 + self.metadata = metadata or {} + + def __repr__(self): + return '[Lane]\n' + str(self.points) + '\n[/Lane]' + + def __call__(self, lane_ys): + lane_xs = self.function(lane_ys) + + lane_xs[(lane_ys < self.min_y) | (lane_ys > self.max_y + )] = self.invalid_value + return lane_xs + + def to_array(self, sample_y_range, img_w, img_h): + self.sample_y = range(sample_y_range[0], sample_y_range[1], + sample_y_range[2]) + sample_y = self.sample_y + img_w, img_h = img_w, img_h + ys = np.array(sample_y) / float(img_h) + xs = self(ys) + valid_mask = (xs >= 0) & (xs < 1) + lane_xs = xs[valid_mask] * img_w + lane_ys = ys[valid_mask] * img_h + lane = np.concatenate( + (lane_xs.reshape(-1, 1), lane_ys.reshape(-1, 1)), axis=1) + return lane + + def __iter__(self): + return self + + def __next__(self): + if self.curr_iter < len(self.points): + self.curr_iter += 1 + return self.points[self.curr_iter - 1] + self.curr_iter = 0 + raise StopIteration + + +COLORS = [ + (255, 0, 0), + (0, 255, 0), + (0, 0, 255), + (255, 255, 0), + (255, 0, 255), + (0, 255, 255), + (128, 255, 0), + (255, 128, 0), + (128, 0, 255), + (255, 0, 128), + (0, 128, 255), + (0, 255, 128), + (128, 255, 255), + (255, 128, 255), + (255, 255, 128), + (60, 180, 0), + (180, 60, 0), + (0, 60, 180), + (0, 180, 60), + (60, 0, 180), + (180, 0, 60), + (255, 0, 0), + (0, 255, 0), + (0, 0, 255), + (255, 255, 0), + (255, 0, 255), + (0, 255, 255), + (128, 255, 0), + (255, 128, 0), + (128, 0, 255), +] + + +def imshow_lanes(img, lanes, show=False, out_file=None, width=4): + lanes_xys = [] + for _, lane in enumerate(lanes): + xys = [] + for x, y in lane: + if x <= 0 or y <= 0: + continue + x, y = int(x), int(y) + xys.append((x, y)) + lanes_xys.append(xys) + lanes_xys.sort(key=lambda xys: xys[0][0] if len(xys) > 0 else 0) + + for idx, xys in enumerate(lanes_xys): + for i in range(1, len(xys)): + cv2.line(img, xys[i - 1], xys[i], COLORS[idx], thickness=width) + + if show: + cv2.imshow('view', img) + cv2.waitKey(0) + + if out_file: + if not os.path.exists(os.path.dirname(out_file)): + os.makedirs(os.path.dirname(out_file)) + cv2.imwrite(out_file, img) diff --git a/ppdet/modeling/losses/__init__.py b/ppdet/modeling/losses/__init__.py index 0e6b31de8..41b3ae0f1 100644 --- a/ppdet/modeling/losses/__init__.py +++ b/ppdet/modeling/losses/__init__.py @@ -31,6 +31,8 @@ from . import probiou_loss from . import cot_loss from . import supcontrast from . import queryinst_loss +from . import clrnet_loss +from . import clrnet_line_iou_loss from .yolo_loss import * from .iou_aware_loss import * @@ -52,3 +54,5 @@ from .probiou_loss import * from .cot_loss import * from .supcontrast import * from .queryinst_loss import * +from .clrnet_loss import * +from .clrnet_line_iou_loss import * \ No newline at end of file diff --git a/ppdet/modeling/losses/clrnet_line_iou_loss.py b/ppdet/modeling/losses/clrnet_line_iou_loss.py new file mode 100644 index 000000000..2a1973d78 --- /dev/null +++ b/ppdet/modeling/losses/clrnet_line_iou_loss.py @@ -0,0 +1,41 @@ +import paddle + + +def line_iou(pred, target, img_w, length=15, aligned=True): + ''' + Calculate the line iou value between predictions and targets + Args: + pred: lane predictions, shape: (num_pred, 72) + target: ground truth, shape: (num_target, 72) + img_w: image width + length: extended radius + aligned: True for iou loss calculation, False for pair-wise ious in assign + ''' + px1 = pred - length + px2 = pred + length + tx1 = target - length + tx2 = target + length + + if aligned: + invalid_mask = target + ovr = paddle.minimum(px2, tx2) - paddle.maximum(px1, tx1) + union = paddle.maximum(px2, tx2) - paddle.minimum(px1, tx1) + else: + num_pred = pred.shape[0] + invalid_mask = target.tile([num_pred, 1, 1]) + + ovr = (paddle.minimum(px2[:, None, :], tx2[None, ...]) - paddle.maximum( + px1[:, None, :], tx1[None, ...])) + union = (paddle.maximum(px2[:, None, :], tx2[None, ...]) - + paddle.minimum(px1[:, None, :], tx1[None, ...])) + + invalid_masks = (invalid_mask < 0) | (invalid_mask >= img_w) + + ovr[invalid_masks] = 0. + union[invalid_masks] = 0. + iou = ovr.sum(axis=-1) / (union.sum(axis=-1) + 1e-9) + return iou + + +def liou_loss(pred, target, img_w, length=15): + return (1 - line_iou(pred, target, img_w, length)).mean() diff --git a/ppdet/modeling/losses/clrnet_loss.py b/ppdet/modeling/losses/clrnet_loss.py new file mode 100644 index 000000000..b4ad39e58 --- /dev/null +++ b/ppdet/modeling/losses/clrnet_loss.py @@ -0,0 +1,283 @@ +import paddle +import paddle.nn as nn +import paddle.nn.functional as F +from ppdet.core.workspace import register +from ppdet.modeling.clrnet_utils import accuracy +from ppdet.modeling.assigners.clrnet_assigner import assign +from ppdet.modeling.losses.clrnet_line_iou_loss import liou_loss + +__all__ = ['CLRNetLoss'] + + +class SoftmaxFocalLoss(nn.Layer): + def __init__(self, gamma, ignore_lb=255, *args, **kwargs): + super(SoftmaxFocalLoss, self).__init__() + self.gamma = gamma + self.nll = nn.NLLLoss(ignore_index=ignore_lb) + + def forward(self, logits, labels): + scores = F.softmax(logits, dim=1) + factor = paddle.pow(1. - scores, self.gamma) + log_score = F.log_softmax(logits, dim=1) + log_score = factor * log_score + loss = self.nll(log_score, labels) + return loss + + +def focal_loss(input: paddle.Tensor, + target: paddle.Tensor, + alpha: float, + gamma: float=2.0, + reduction: str='none', + eps: float=1e-8) -> paddle.Tensor: + r"""Function that computes Focal loss. + + See :class:`~kornia.losses.FocalLoss` for details. + """ + if not paddle.is_tensor(input): + raise TypeError("Input type is not a torch.Tensor. Got {}".format( + type(input))) + + if not len(input.shape) >= 2: + raise ValueError("Invalid input shape, we expect BxCx*. Got: {}".format( + input.shape)) + + if input.shape[0] != target.shape[0]: + raise ValueError( + 'Expected input batch_size ({}) to match target batch_size ({}).'. + format(input.shape[0], target.shape[0])) + + n = input.shape[0] + out_size = (n, ) + tuple(input.shape[2:]) + if target.shape[1:] != input.shape[2:]: + raise ValueError('Expected target size {}, got {}'.format(out_size, + target.shape)) + if (isinstance(input.place, paddle.CUDAPlace) and + isinstance(target.place, paddle.CPUPlace)) | (isinstance( + input.place, paddle.CPUPlace) and isinstance(target.place, + paddle.CUDAPlace)): + raise ValueError( + "input and target must be in the same device. Got: {} and {}". + format(input.place, target.place)) + + # compute softmax over the classes axis + input_soft: paddle.Tensor = F.softmax(input, axis=1) + eps + + # create the labels one hot tensor + target_one_hot: paddle.Tensor = paddle.to_tensor( + F.one_hot( + target, num_classes=input.shape[1]).cast(input.dtype), + place=input.place) + + # compute the actual focal loss + weight = paddle.pow(-input_soft + 1., gamma) + + focal = -alpha * weight * paddle.log(input_soft) + loss_tmp = paddle.sum(target_one_hot * focal, axis=1) + + if reduction == 'none': + loss = loss_tmp + elif reduction == 'mean': + loss = paddle.mean(loss_tmp) + elif reduction == 'sum': + loss = paddle.sum(loss_tmp) + else: + raise NotImplementedError("Invalid reduction mode: {}".format( + reduction)) + return loss + + +class FocalLoss(nn.Layer): + r"""Criterion that computes Focal loss. + + According to [1], the Focal loss is computed as follows: + + .. math:: + + \text{FL}(p_t) = -\alpha_t (1 - p_t)^{\gamma} \, \text{log}(p_t) + + where: + - :math:`p_t` is the model's estimated probability for each class. + + + Arguments: + alpha (float): Weighting factor :math:`\alpha \in [0, 1]`. + gamma (float): Focusing parameter :math:`\gamma >= 0`. + reduction (str, optional): Specifies the reduction to apply to the + output: ‘none’ | ‘mean’ | ‘sum’. ‘none’: no reduction will be applied, + ‘mean’: the sum of the output will be divided by the number of elements + in the output, ‘sum’: the output will be summed. Default: ‘none’. + + Shape: + - Input: :math:`(N, C, *)` where C = number of classes. + - Target: :math:`(N, *)` where each value is + :math:`0 ≤ targets[i] ≤ C−1`. + + Examples: + >>> N = 5 # num_classes + >>> kwargs = {"alpha": 0.5, "gamma": 2.0, "reduction": 'mean'} + >>> loss = kornia.losses.FocalLoss(**kwargs) + >>> input = torch.randn(1, N, 3, 5, requires_grad=True) + >>> target = torch.empty(1, 3, 5, dtype=torch.long).random_(N) + >>> output = loss(input, target) + >>> output.backward() + + References: + [1] https://arxiv.org/abs/1708.02002 + """ + + def __init__(self, alpha: float, gamma: float=2.0, + reduction: str='none') -> None: + super(FocalLoss, self).__init__() + self.alpha: float = alpha + self.gamma: float = gamma + self.reduction: str = reduction + self.eps: float = 1e-6 + + def forward( # type: ignore + self, input: paddle.Tensor, target: paddle.Tensor) -> paddle.Tensor: + return focal_loss(input, target, self.alpha, self.gamma, self.reduction, + self.eps) + + +@register +class CLRNetLoss(nn.Layer): + __shared__ = ['img_w', 'img_h', 'num_classes', 'num_points'] + + def __init__(self, + cls_loss_weight=2.0, + xyt_loss_weight=0.2, + iou_loss_weight=2.0, + seg_loss_weight=1.0, + refine_layers=3, + num_points=72, + img_w=800, + img_h=320, + num_classes=5, + ignore_label=255, + bg_weight=0.4): + super(CLRNetLoss, self).__init__() + self.cls_loss_weight = cls_loss_weight + self.xyt_loss_weight = xyt_loss_weight + self.iou_loss_weight = iou_loss_weight + self.seg_loss_weight = seg_loss_weight + self.refine_layers = refine_layers + self.img_w = img_w + self.img_h = img_h + self.n_strips = num_points - 1 + self.num_classes = num_classes + self.ignore_label = ignore_label + weights = paddle.ones(shape=[self.num_classes]) + weights[0] = bg_weight + self.criterion = nn.NLLLoss( + ignore_index=self.ignore_label, weight=weights) + + def forward(self, output, batch): + predictions_lists = output['predictions_lists'] + targets = batch['lane_line'].clone() + cls_criterion = FocalLoss(alpha=0.25, gamma=2.0) + cls_loss = paddle.to_tensor(0.0) + reg_xytl_loss = paddle.to_tensor(0.0) + iou_loss = paddle.to_tensor(0.0) + cls_acc = [] + cls_acc_stage = [] + for stage in range(self.refine_layers): + predictions_list = predictions_lists[stage] + for predictions, target in zip(predictions_list, targets): + target = target[target[:, 1] == 1] + + if len(target) == 0: + # If there are no targets, all predictions have to be negatives (i.e., 0 confidence) + cls_target = paddle.zeros( + [predictions.shape[0]], dtype='int64') + cls_pred = predictions[:, :2] + cls_loss = cls_loss + cls_criterion(cls_pred, + cls_target).sum() + continue + + with paddle.no_grad(): + matched_row_inds, matched_col_inds = assign( + predictions, target, self.img_w, self.img_h) + + # classification targets + cls_target = paddle.zeros([predictions.shape[0]], dtype='int64') + cls_target[matched_row_inds] = 1 + cls_pred = predictions[:, :2] + + # regression targets -> [start_y, start_x, theta] (all transformed to absolute values), only on matched pairs + reg_yxtl = predictions.index_select(matched_row_inds)[..., 2:6] + + reg_yxtl[:, 0] *= self.n_strips + reg_yxtl[:, 1] *= (self.img_w - 1) + reg_yxtl[:, 2] *= 180 + reg_yxtl[:, 3] *= self.n_strips + + target_yxtl = target.index_select(matched_col_inds)[..., 2: + 6].clone() + + # regression targets -> S coordinates (all transformed to absolute values) + reg_pred = predictions.index_select(matched_row_inds)[..., 6:] + reg_pred *= (self.img_w - 1) + reg_targets = target.index_select(matched_col_inds)[..., + 6:].clone() + + with paddle.no_grad(): + predictions_starts = paddle.clip( + (predictions.index_select(matched_row_inds)[..., 2] * + self.n_strips).round().cast("int64"), + min=0, + max=self. + n_strips) # ensure the predictions starts is valid + + target_starts = ( + target.index_select(matched_col_inds)[..., 2] * + self.n_strips).round().cast("int64") + target_yxtl[:, -1] -= ( + predictions_starts - target_starts) # reg length + + # Loss calculation + cls_loss = cls_loss + cls_criterion( + cls_pred, cls_target).sum() / target.shape[0] + + target_yxtl[:, 0] *= self.n_strips + target_yxtl[:, 2] *= 180 + + reg_xytl_loss = reg_xytl_loss + F.smooth_l1_loss( + input=reg_yxtl, label=target_yxtl, reduction='none').mean() + + iou_loss = iou_loss + liou_loss( + reg_pred, reg_targets, self.img_w, length=15) + + cls_accuracy = accuracy(cls_pred, cls_target) + cls_acc_stage.append(cls_accuracy) + + cls_acc.append(sum(cls_acc_stage) / (len(cls_acc_stage) + 1e-5)) + + # extra segmentation loss + seg_loss = self.criterion( + F.log_softmax( + output['seg'], axis=1), batch['seg'].cast('int64')) + + cls_loss /= (len(targets) * self.refine_layers) + reg_xytl_loss /= (len(targets) * self.refine_layers) + iou_loss /= (len(targets) * self.refine_layers) + + loss = cls_loss * self.cls_loss_weight \ + + reg_xytl_loss * self.xyt_loss_weight \ + + seg_loss * self.seg_loss_weight \ + + iou_loss * self.iou_loss_weight + + return_value = { + 'loss': loss, + 'cls_loss': cls_loss * self.cls_loss_weight, + 'reg_xytl_loss': reg_xytl_loss * self.xyt_loss_weight, + 'seg_loss': seg_loss * self.seg_loss_weight, + 'iou_loss': iou_loss * self.iou_loss_weight + } + + for i in range(self.refine_layers): + if not isinstance(cls_acc[i], paddle.Tensor): + cls_acc[i] = paddle.to_tensor(cls_acc[i]) + return_value['stage_{}_acc'.format(i)] = cls_acc[i] + + return return_value diff --git a/ppdet/modeling/necks/__init__.py b/ppdet/modeling/necks/__init__.py index 478efec98..afd2a9545 100644 --- a/ppdet/modeling/necks/__init__.py +++ b/ppdet/modeling/necks/__init__.py @@ -23,6 +23,7 @@ from . import es_pan from . import lc_pan from . import custom_pan from . import dilated_encoder +from . import clrnet_fpn from .fpn import * from .yolo_fpn import * @@ -37,3 +38,4 @@ from .lc_pan import * from .custom_pan import * from .dilated_encoder import * from .channel_mapper import * +from .clrnet_fpn import * diff --git a/ppdet/modeling/necks/clrnet_fpn.py b/ppdet/modeling/necks/clrnet_fpn.py new file mode 100644 index 000000000..936c7e7c7 --- /dev/null +++ b/ppdet/modeling/necks/clrnet_fpn.py @@ -0,0 +1,254 @@ +# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import paddle.nn as nn +import paddle.nn.functional as F +from paddle import ParamAttr +from paddle.nn.initializer import XavierUniform +from ppdet.modeling.initializer import kaiming_normal_, constant_ +from ppdet.core.workspace import register, serializable +from ppdet.modeling.layers import ConvNormLayer +from ppdet.modeling.shape_spec import ShapeSpec + +__all__ = ['CLRFPN'] + + +@register +@serializable +class CLRFPN(nn.Layer): + """ + Feature Pyramid Network, see https://arxiv.org/abs/1612.03144 + Args: + in_channels (list[int]): input channels of each level which can be + derived from the output shape of backbone by from_config + out_channel (int): output channel of each level + spatial_scales (list[float]): the spatial scales between input feature + maps and original input image which can be derived from the output + shape of backbone by from_config + has_extra_convs (bool): whether to add extra conv to the last level. + default False + extra_stage (int): the number of extra stages added to the last level. + default 1 + use_c5 (bool): Whether to use c5 as the input of extra stage, + otherwise p5 is used. default True + norm_type (string|None): The normalization type in FPN module. If + norm_type is None, norm will not be used after conv and if + norm_type is string, bn, gn, sync_bn are available. default None + norm_decay (float): weight decay for normalization layer weights. + default 0. + freeze_norm (bool): whether to freeze normalization layer. + default False + relu_before_extra_convs (bool): whether to add relu before extra convs. + default False + + """ + + def __init__(self, + in_channels, + out_channel, + spatial_scales=[0.25, 0.125, 0.0625, 0.03125], + has_extra_convs=False, + extra_stage=1, + use_c5=True, + norm_type=None, + norm_decay=0., + freeze_norm=False, + relu_before_extra_convs=True): + super(CLRFPN, self).__init__() + self.out_channel = out_channel + for s in range(extra_stage): + spatial_scales = spatial_scales + [spatial_scales[-1] / 2.] + self.spatial_scales = spatial_scales + self.has_extra_convs = has_extra_convs + self.extra_stage = extra_stage + self.use_c5 = use_c5 + self.relu_before_extra_convs = relu_before_extra_convs + self.norm_type = norm_type + self.norm_decay = norm_decay + self.freeze_norm = freeze_norm + self.in_channels = in_channels + self.lateral_convs = [] + self.fpn_convs = [] + fan = out_channel * 3 * 3 + + # stage index 0,1,2,3 stands for res2,res3,res4,res5 on ResNet Backbone + # 0 <= st_stage < ed_stage <= 3 + st_stage = 4 - len(in_channels) + ed_stage = st_stage + len(in_channels) - 1 + + for i in range(st_stage, ed_stage + 1): + # if i == 3: + # lateral_name = 'fpn_inner_res5_sum' + # else: + # lateral_name = 'fpn_inner_res{}_sum_lateral'.format(i + 2) + lateral_name = "lateral_convs.{}.conv".format(i - 1) + in_c = in_channels[i - st_stage] + if self.norm_type is not None: + lateral = self.add_sublayer( + lateral_name, + ConvNormLayer( + ch_in=in_c, + ch_out=out_channel, + filter_size=1, + stride=1, + norm_type=self.norm_type, + norm_decay=self.norm_decay, + freeze_norm=self.freeze_norm, + initializer=XavierUniform(fan_out=in_c))) + else: + lateral = self.add_sublayer( + lateral_name, + nn.Conv2D( + in_channels=in_c, + out_channels=out_channel, + kernel_size=1, + weight_attr=ParamAttr( + initializer=XavierUniform(fan_out=in_c)))) + self.lateral_convs.append(lateral) + + fpn_name = "fpn_convs.{}.conv".format(i - 1) + if self.norm_type is not None: + fpn_conv = self.add_sublayer( + fpn_name, + ConvNormLayer( + ch_in=out_channel, + ch_out=out_channel, + filter_size=3, + stride=1, + norm_type=self.norm_type, + norm_decay=self.norm_decay, + freeze_norm=self.freeze_norm, + initializer=XavierUniform(fan_out=fan))) + else: + fpn_conv = self.add_sublayer( + fpn_name, + nn.Conv2D( + in_channels=out_channel, + out_channels=out_channel, + kernel_size=3, + padding=1, + weight_attr=ParamAttr( + initializer=XavierUniform(fan_out=fan)))) + self.fpn_convs.append(fpn_conv) + + # add extra conv levels for RetinaNet(use_c5)/FCOS(use_p5) + if self.has_extra_convs: + for i in range(self.extra_stage): + lvl = ed_stage + 1 + i + if i == 0 and self.use_c5: + in_c = in_channels[-1] + else: + in_c = out_channel + extra_fpn_name = 'fpn_{}'.format(lvl + 2) + if self.norm_type is not None: + extra_fpn_conv = self.add_sublayer( + extra_fpn_name, + ConvNormLayer( + ch_in=in_c, + ch_out=out_channel, + filter_size=3, + stride=2, + norm_type=self.norm_type, + norm_decay=self.norm_decay, + freeze_norm=self.freeze_norm, + initializer=XavierUniform(fan_out=fan))) + else: + extra_fpn_conv = self.add_sublayer( + extra_fpn_name, + nn.Conv2D( + in_channels=in_c, + out_channels=out_channel, + kernel_size=3, + stride=2, + padding=1, + weight_attr=ParamAttr( + initializer=XavierUniform(fan_out=fan)))) + self.fpn_convs.append(extra_fpn_conv) + self.init_weights() + + def init_weights(self): + for m in self.lateral_convs: + if isinstance(m, (nn.Conv1D, nn.Conv2D)): + kaiming_normal_( + m.weight, a=0, mode='fan_out', nonlinearity='relu') + if m.bias is not None: + constant_(m.bias, value=0.) + elif isinstance(m, (nn.BatchNorm1D, nn.BatchNorm2D)): + constant_(m.weight, value=1) + constant_(m.bias, value=0) + for m in self.fpn_convs: + if isinstance(m, (nn.Conv1D, nn.Conv2D)): + kaiming_normal_( + m.weight, a=0, mode='fan_out', nonlinearity='relu') + if m.bias is not None: + constant_(m.bias, value=0.) + elif isinstance(m, (nn.BatchNorm1D, nn.BatchNorm2D)): + constant_(m.weight, value=1) + constant_(m.bias, value=0) + + @classmethod + def from_config(cls, cfg, input_shape): + return {} + + def forward(self, body_feats): + laterals = [] + if len(body_feats) > len(self.in_channels): + for _ in range(len(body_feats) - len(self.in_channels)): + del body_feats[0] + num_levels = len(body_feats) + # print("body_feats",num_levels) + for i in range(num_levels): + laterals.append(self.lateral_convs[i](body_feats[i])) + + for i in range(1, num_levels): + lvl = num_levels - i + upsample = F.interpolate( + laterals[lvl], + scale_factor=2., + mode='nearest', ) + laterals[lvl - 1] += upsample + + fpn_output = [] + for lvl in range(num_levels): + fpn_output.append(self.fpn_convs[lvl](laterals[lvl])) + + if self.extra_stage > 0: + # use max pool to get more levels on top of outputs (Faster R-CNN, Mask R-CNN) + if not self.has_extra_convs: + assert self.extra_stage == 1, 'extra_stage should be 1 if FPN has not extra convs' + fpn_output.append(F.max_pool2d(fpn_output[-1], 1, stride=2)) + # add extra conv levels for RetinaNet(use_c5)/FCOS(use_p5) + else: + if self.use_c5: + extra_source = body_feats[-1] + else: + extra_source = fpn_output[-1] + fpn_output.append(self.fpn_convs[num_levels](extra_source)) + + for i in range(1, self.extra_stage): + if self.relu_before_extra_convs: + fpn_output.append(self.fpn_convs[num_levels + i](F.relu( + fpn_output[-1]))) + else: + fpn_output.append(self.fpn_convs[num_levels + i]( + fpn_output[-1])) + return fpn_output + + @property + def out_shape(self): + return [ + ShapeSpec( + channels=self.out_channel, stride=1. / s) + for s in self.spatial_scales + ] diff --git a/ppdet/utils/download.py b/ppdet/utils/download.py index 8fb95afa3..5f3665fc8 100644 --- a/ppdet/utils/download.py +++ b/ppdet/utils/download.py @@ -101,7 +101,8 @@ DATASETS = { '8a3a353c2c54a2284ad7d2780b65f6a6', ), ], ['annotations', 'images']), 'coco_ce': ([( 'https://paddledet.bj.bcebos.com/data/coco_ce.tar', - 'eadd1b79bc2f069f2744b1dd4e0c0329', ), ], []) + 'eadd1b79bc2f069f2744b1dd4e0c0329', ), ], []), + 'culane': ([('https://bj.bcebos.com/v1/paddledet/data/culane.tar', None, ), ], []) } DOWNLOAD_DATASETS_LIST = DATASETS.keys() diff --git a/requirements.txt b/requirements.txt index f6297b6f7..a094c54ea 100644 --- a/requirements.txt +++ b/requirements.txt @@ -18,3 +18,6 @@ sklearn==0.0 # for vehicleplate in deploy/pipeline/ppvehicle pyclipper + +# for culane data augumetation +imgaug>=0.4.0 \ No newline at end of file diff --git a/tools/infer_culane.py b/tools/infer_culane.py new file mode 100644 index 000000000..5f629467e --- /dev/null +++ b/tools/infer_culane.py @@ -0,0 +1,165 @@ +# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import os +import sys + +# add python path of PaddleDetection to sys.path +parent_path = os.path.abspath(os.path.join(__file__, *(['..'] * 2))) +sys.path.insert(0, parent_path) + +# ignore warning log +import warnings +warnings.filterwarnings('ignore') +import glob +import ast + +import paddle +from ppdet.core.workspace import load_config, merge_config +from ppdet.engine import Trainer +from ppdet.utils.check import check_gpu, check_npu, check_xpu, check_mlu, check_version, check_config +from ppdet.utils.cli import ArgsParser, merge_args +from ppdet.slim import build_slim_model + +from ppdet.utils.logger import setup_logger +logger = setup_logger('train') + + +def parse_args(): + parser = ArgsParser() + parser.add_argument( + "--infer_dir", + type=str, + default=None, + help="Directory for images to perform inference on.") + parser.add_argument( + "--infer_img", + type=str, + default=None, + help="Image path, has higher priority over --infer_dir") + parser.add_argument( + "--output_dir", + type=str, + default="output", + help="Directory for storing the output visualization files.") + parser.add_argument( + "--save_results", + type=bool, + default=False, + help="Whether to save inference results to output_dir.") + parser.add_argument( + "--visualize", + type=ast.literal_eval, + default=True, + help="Whether to save visualize results to output_dir.") + args = parser.parse_args() + return args + + +def get_test_images(infer_dir, infer_img): + """ + Get image path list in TEST mode + """ + assert infer_img is not None or infer_dir is not None, \ + "--infer_img or --infer_dir should be set" + assert infer_img is None or os.path.isfile(infer_img), \ + "{} is not a file".format(infer_img) + assert infer_dir is None or os.path.isdir(infer_dir), \ + "{} is not a directory".format(infer_dir) + + # infer_img has a higher priority + if infer_img and os.path.isfile(infer_img): + return [infer_img] + + images = set() + infer_dir = os.path.abspath(infer_dir) + assert os.path.isdir(infer_dir), \ + "infer_dir {} is not a directory".format(infer_dir) + exts = ['jpg', 'jpeg', 'png', 'bmp'] + exts += [ext.upper() for ext in exts] + for ext in exts: + images.update(glob.glob('{}/*.{}'.format(infer_dir, ext))) + images = list(images) + + assert len(images) > 0, "no image found in {}".format(infer_dir) + logger.info("Found {} inference images in total.".format(len(images))) + + return images + + +def run(FLAGS, cfg): + # build trainer + trainer = Trainer(cfg, mode='test') + + # load weights + trainer.load_weights(cfg.weights) + + # get inference images + images = get_test_images(FLAGS.infer_dir, FLAGS.infer_img) + + trainer.predict_culane( + images, + output_dir=FLAGS.output_dir, + save_results=FLAGS.save_results, + visualize=FLAGS.visualize) + + +def main(): + FLAGS = parse_args() + cfg = load_config(FLAGS.config) + merge_args(cfg, FLAGS) + merge_config(FLAGS.opt) + + # disable npu in config by default + if 'use_npu' not in cfg: + cfg.use_npu = False + + # disable xpu in config by default + if 'use_xpu' not in cfg: + cfg.use_xpu = False + + if 'use_gpu' not in cfg: + cfg.use_gpu = False + + # disable mlu in config by default + if 'use_mlu' not in cfg: + cfg.use_mlu = False + + if cfg.use_gpu: + place = paddle.set_device('gpu') + elif cfg.use_npu: + place = paddle.set_device('npu') + elif cfg.use_xpu: + place = paddle.set_device('xpu') + elif cfg.use_mlu: + place = paddle.set_device('mlu') + else: + place = paddle.set_device('cpu') + + check_config(cfg) + check_gpu(cfg.use_gpu) + check_npu(cfg.use_npu) + check_xpu(cfg.use_xpu) + check_mlu(cfg.use_mlu) + check_version() + + run(FLAGS, cfg) + + +if __name__ == '__main__': + main() \ No newline at end of file -- GitLab