diff --git a/README.md b/README.md index 7fe1a2a7874706de3aba937211c99984714e3794..31c0e8cf2fe234ff2bbdcc2b0683178a5ecba6ab 100644 --- a/README.md +++ b/README.md @@ -1,83 +1,124 @@ -# PaddleSeg 语义分割库 +# PaddleSeg 图像分割库 [![Build Status](https://travis-ci.org/PaddlePaddle/PaddleSeg.svg?branch=master)](https://travis-ci.org/PaddlePaddle/PaddleSeg) [![License](https://img.shields.io/badge/license-Apache%202-blue.svg)](LICENSE) +[![Version](https://img.shields.io/github/release/PaddlePaddle/PaddleSeg.svg)](https://github.com/PaddlePaddle/PaddleSeg/releases) ## 简介 PaddleSeg是基于[PaddlePaddle](https://www.paddlepaddle.org.cn)开发的语义分割库,覆盖了DeepLabv3+, U-Net, ICNet三类主流的分割模型。通过统一的配置,帮助用户更便捷地完成从训练到部署的全流程图像分割应用。 -具备高性能、丰富的数据增强、工业级部署、全流程应用的特点。 +PaddleSeg具备高性能、丰富的数据增强、工业级部署、全流程应用的特点: - **丰富的数据增强** - - 基于百度视觉技术部的实际业务经验,内置10+种数据增强策略,可结合实际业务场景进行定制组合,提升模型泛化能力和鲁棒性。 - +基于百度视觉技术部的实际业务经验,内置10+种数据增强策略,可结合实际业务场景进行定制组合,提升模型泛化能力和鲁棒性。 + - **主流模型覆盖** - - 支持U-Net, DeepLabv3+, ICNet三类主流分割网络,结合预训练模型和可调节的骨干网络,满足不同性能和精度的要求。 +支持U-Net, DeepLabv3+, ICNet三类主流分割网络,结合预训练模型和可调节的骨干网络,满足不同性能和精度的要求。 - **高性能** - - PaddleSeg支持多进程IO、多卡并行、多卡Batch Norm同步等训练加速策略,结合飞桨核心框架的显存优化算法,可以大幅度减少分割模型的显存开销,更快完成分割模型训练。 - -- **工业级部署** +PaddleSeg支持多进程IO、多卡并行、跨卡Batch Norm同步等训练加速策略,结合飞桨核心框架的显存优化功能,可以大幅度减少分割模型的显存开销,更快完成分割模型训练。 - - 基于[Paddle Serving](https://github.com/PaddlePaddle/Serving)和PaddlePaddle高性能预测引擎,结合百度开放的AI能力,轻松搭建人像分割和车道线分割服务。 +- **工业级部署** +基于[Paddle Serving](https://github.com/PaddlePaddle/Serving)和PaddlePaddle高性能预测引擎,结合百度开放的AI能力,轻松搭建人像分割和车道线分割服务。 -更多模型信息与技术细节请查看[模型介绍](./docs/models.md)和[预训练模型](./docs/model_zoo.md) +
-## AI Studio教程 +## 使用教程 -### 快速开始 +我们提供了一系列的使用教程,来说明如何使用PaddleSeg完成语义分割模型的训练、评估、部署。 -通过 [PaddleSeg人像分割](https://aistudio.baidu.com/aistudio/projectDetail/100798) 教程可快速体验PaddleSeg人像分割模型的效果。 +这一系列的文档被分为**快速入门**、**基础功能**、**预测部署**、**高级功能**四个部分,四个教程由浅至深地介绍PaddleSeg的设计思路和使用方法。 -### 入门教程 +### 快速入门 -入门教程以经典的U-Net模型为例, 结合Oxford-IIIT宠物数据集,快速熟悉PaddleSeg使用流程, 详情请点击[U-Net宠物分割](https://aistudio.baidu.com/aistudio/projectDetail/102889)。 +* [安装说明](./docs/installation.md) +* [训练/评估/可视化](./docs/usage.md) -### 高级教程 +### 基础功能 -高级教程以DeepLabv3+模型为例,结合Cityscapes数据集,快速了解ASPP, Backbone网络切换,多卡Batch Norm同步等策略,详情请点击[DeepLabv3+图像分割](https://aistudio.baidu.com/aistudio/projectDetail/101696)。 +* [分割模型介绍](./docs/models.md) +* [预训练模型列表](./docs/model_zoo.md) +* [自定义数据的准备与标注](./docs/data_prepare.md) +* [数据和配置校验](./docs/check.md) +* [如何训练DeepLabv3+](./turtorial/finetune_deeplabv3plus.md) +* [如何训练U-Net](./turtorial/finetune_unet.md) +* [如何训练ICNet](./turtorial/finetune_icnet.md) +* [如何训练PSPNet](./turtorial/finetune_pspnet.md) -### 垂类模型 +### 预测部署 -更多特色垂类分割模型如LIP人体部件分割、人像分割、车道线分割模型可以参考[contrib](./contrib) +* [模型导出](./docs/model_export.md) +* [C++预测库使用](./inference) +* [PaddleSeg Serving服务化部署](./serving) -## 使用文档 +### 高级功能 -* [安装说明](./docs/installation.md) -* [数据准备](./docs/data_prepare.md) -* [数据增强](./docs/data_aug.md) -* [预训练模型](./docs/model_zoo.md) -* [训练/评估/预测(可视化)](./docs/usage.md) -* [预测库集成](./inference/README.md) -* [服务端部署](./serving/README.md) -* [垂类分割模型](./contrib/README.md) +* [PaddleSeg的数据增强](./docs/data_aug.md) +* [特色垂类模型使用](./contrib) +
## FAQ -#### Q:图像分割的数据增强如何配置,unpadding, step-scaling, range-scaling的原理是什么? +#### Q: 安装requirements.txt指定的依赖包时,部分包提示找不到? + +A: 可能是pip源的问题,这种情况下建议切换为官方源,或者通过`pip install -r requirements.txt -i `指定其他源地址。 + +#### Q:图像分割的数据增强如何配置,Unpadding, StepScaling, RangeScaling的原理是什么? + +A: 更详细数据增强文档可以参考[数据增强](./docs/data_aug.md) + +#### Q: 训练时因为某些原因中断了,如何恢复训练? -A: 数据增强的配置可以参考文档[数据增强](./docs/data_aug.md) +A: 启动训练脚本时通过命令行覆盖TRAIN.RESUME_MODEL_DIR配置为模型checkpoint目录即可, 以下代码示例第100轮重新恢复训练: +``` +python pdseg/train.py --cfg xxx.yaml TRAIN.RESUME_MODEL_DIR /PATH/TO/MODEL_CKPT/100 +``` #### Q: 预测时图片过大,导致显存不足如何处理? -A: 降低Batch size,使用Group Norm策略等。 +A: 降低Batch size,使用Group Norm策略;请注意训练过程中当`DEFAULT_NORM_TYPE`选择`bn`时,为了Batch Norm计算稳定性,batch size需要满足>=2 + +
+ +## 在线体验 + +PaddleSeg在AI Studio平台上提供了在线体验的教程,欢迎体验: + +|教程|链接| +|-|-| +|U-Net宠物分割|[点击体验](https://aistudio.baidu.com/aistudio/projectDetail/102889)| +|DeepLabv3+图像分割|[点击体验](https://aistudio.baidu.com/aistudio/projectDetail/101696)| +|PaddleSeg特色垂类模型|[点击体验](https://aistudio.baidu.com/aistudio/projectdetail/115541)| + +
+ +## 交流与反馈 +* 欢迎您通过Github Issues来提交问题、报告与建议 +* 微信公众号:飞桨PaddlePaddle +* QQ群: 796771754 + +

     

+

   微信公众号                官方技术交流QQ群

+ +* 论坛: 欢迎大家在[PaddlePaddle论坛](https://ai.baidu.com/forum/topic/list/168)分享在使用PaddlePaddle中遇到的问题和经验, 营造良好的论坛氛围 ## 更新日志 -### 2019.08.26 +* 2019.09.10 -#### v0.1.0 + **`v0.1.0`** + * PaddleSeg分割库初始版本发布,包含DeepLabv3+, U-Net, ICNet三类分割模型, 其中DeepLabv3+支持Xception, MobileNet两种可调节的骨干网络。 + * CVPR19 LIP人体部件分割比赛冠军预测模型发布[ACE2P](./contrib/ACE2P) + * 预置基于DeepLabv3+网络的[人像分割](./contrib/HumanSeg/)和[车道线分割](./contrib/RoadLine)预测模型发布 -* PaddleSeg分割库初始版本发布,包含DeepLabv3+, U-Net, ICNet三类分割模型, 其中DeepLabv3+支持Xception, MobileNet两种可调节的骨干网络。 -* CVPR 19' LIP人体部件分割比赛冠军预测模型发布[ACE2P](./contrib/ACE2P) -* 预置基于DeepLabv3+网络的人像分割和车道线分割预测模型发布 +
## 如何贡献代码 diff --git a/configs/deeplabv3p_mobilenet-1-0_pet.yaml b/configs/deeplabv3p_mobilenet-1-0_pet.yaml new file mode 100644 index 0000000000000000000000000000000000000000..ae7ec59adc83ba87127847e295a0811d2964edb5 --- /dev/null +++ b/configs/deeplabv3p_mobilenet-1-0_pet.yaml @@ -0,0 +1,47 @@ +TRAIN_CROP_SIZE: (512, 512) # (width, height), for unpadding rangescaling and stepscaling +EVAL_CROP_SIZE: (512, 512) # (width, height), for unpadding rangescaling and stepscaling +AUG: + AUG_METHOD: "unpadding" # choice unpadding rangescaling and stepscaling + FIX_RESIZE_SIZE: (512, 512) # (width, height), for unpadding + + INF_RESIZE_VALUE: 500 # for rangescaling + MAX_RESIZE_VALUE: 600 # for rangescaling + MIN_RESIZE_VALUE: 400 # for rangescaling + + MAX_SCALE_FACTOR: 1.25 # for stepscaling + MIN_SCALE_FACTOR: 0.75 # for stepscaling + SCALE_STEP_SIZE: 0.25 # for stepscaling + MIRROR: True +BATCH_SIZE: 4 +DATASET: + DATA_DIR: "./dataset/mini_pet/" + IMAGE_TYPE: "rgb" # choice rgb or rgba + NUM_CLASSES: 3 + TEST_FILE_LIST: "./dataset/mini_pet/file_list/test_list.txt" + TRAIN_FILE_LIST: "./dataset/mini_pet/file_list/train_list.txt" + VAL_FILE_LIST: "./dataset/mini_pet/file_list/val_list.txt" + VIS_FILE_LIST: "./dataset/mini_pet/file_list/test_list.txt" + IGNORE_INDEX: 255 + SEPARATOR: " " +FREEZE: + MODEL_FILENAME: "__model__" + PARAMS_FILENAME: "__params__" +MODEL: + MODEL_NAME: "deeplabv3p" + DEFAULT_NORM_TYPE: "bn" + DEEPLAB: + BACKBONE: "mobilenet" + DEPTH_MULTIPLIER: 1.0 + ENCODER_WITH_ASPP: False + ENABLE_DECODER: False +TRAIN: + PRETRAINED_MODEL_DIR: "./pretrained_model/deeplabv3p_mobilenetv2-1-0_bn_cityscapes/" + MODEL_SAVE_DIR: "./saved_model/deeplabv3p_mobilenetv2-1-0_bn_pet/" + SNAPSHOT_EPOCH: 10 +TEST: + TEST_MODEL: "./saved_model/deeplabv3p_mobilenetv2-1-0_bn_pet/final" +SOLVER: + NUM_EPOCHS: 100 + LR: 0.005 + LR_POLICY: "poly" + OPTIMIZER: "sgd" diff --git a/configs/deeplabv3p_xception65_pet.yaml b/configs/deeplabv3p_xception65_pet.yaml new file mode 100644 index 0000000000000000000000000000000000000000..1b574497ea882c86c7e5785e16de976e5b33a50f --- /dev/null +++ b/configs/deeplabv3p_xception65_pet.yaml @@ -0,0 +1,44 @@ +TRAIN_CROP_SIZE: (512, 512) # (width, height), for unpadding rangescaling and stepscaling +EVAL_CROP_SIZE: (512, 512) # (width, height), for unpadding rangescaling and stepscaling +AUG: + AUG_METHOD: "unpadding" # choice unpadding rangescaling and stepscaling + FIX_RESIZE_SIZE: (512, 512) # (width, height), for unpadding + + INF_RESIZE_VALUE: 500 # for rangescaling + MAX_RESIZE_VALUE: 600 # for rangescaling + MIN_RESIZE_VALUE: 400 # for rangescaling + + MAX_SCALE_FACTOR: 1.25 # for stepscaling + MIN_SCALE_FACTOR: 0.75 # for stepscaling + SCALE_STEP_SIZE: 0.25 # for stepscaling + MIRROR: True +BATCH_SIZE: 4 +DATASET: + DATA_DIR: "./dataset/mini_pet/" + IMAGE_TYPE: "rgb" # choice rgb or rgba + NUM_CLASSES: 3 + TEST_FILE_LIST: "./dataset/mini_pet/file_list/test_list.txt" + TRAIN_FILE_LIST: "./dataset/mini_pet/file_list/train_list.txt" + VAL_FILE_LIST: "./dataset/mini_pet/file_list/val_list.txt" + VIS_FILE_LIST: "./dataset/mini_pet/file_list/test_list.txt" + IGNORE_INDEX: 255 + SEPARATOR: " " +FREEZE: + MODEL_FILENAME: "__model__" + PARAMS_FILENAME: "__params__" +MODEL: + MODEL_NAME: "deeplabv3p" + DEFAULT_NORM_TYPE: "bn" + DEEPLAB: + BACKBONE: "xception_65" +TRAIN: + PRETRAINED_MODEL_DIR: "./pretrained_model/deeplabv3p_xception65_bn_coco/" + MODEL_SAVE_DIR: "./saved_model/deeplabv3p_xception65_bn_pet/" + SNAPSHOT_EPOCH: 10 +TEST: + TEST_MODEL: "./saved_model/deeplabv3p_xception65_bn_pet/final" +SOLVER: + NUM_EPOCHS: 100 + LR: 0.005 + LR_POLICY: "poly" + OPTIMIZER: "sgd" diff --git a/configs/icnet_pet.yaml b/configs/icnet_pet.yaml new file mode 100644 index 0000000000000000000000000000000000000000..0398d131ca12aea7902ec7be6542650377201c25 --- /dev/null +++ b/configs/icnet_pet.yaml @@ -0,0 +1,45 @@ +TRAIN_CROP_SIZE: (512, 512) # (width, height), for unpadding rangescaling and stepscaling +EVAL_CROP_SIZE: (512, 512) # (width, height), for unpadding rangescaling and stepscaling +AUG: + AUG_METHOD: "unpadding" # choice unpadding rangescaling and stepscaling + FIX_RESIZE_SIZE: (512, 512) # (width, height), for unpadding + + INF_RESIZE_VALUE: 500 # for rangescaling + MAX_RESIZE_VALUE: 600 # for rangescaling + MIN_RESIZE_VALUE: 400 # for rangescaling + + MAX_SCALE_FACTOR: 1.25 # for stepscaling + MIN_SCALE_FACTOR: 0.75 # for stepscaling + SCALE_STEP_SIZE: 0.25 # for stepscaling + MIRROR: True +BATCH_SIZE: 4 +DATASET: + DATA_DIR: "./dataset/mini_pet/" + IMAGE_TYPE: "rgb" # choice rgb or rgba + NUM_CLASSES: 3 + TEST_FILE_LIST: "./dataset/mini_pet/file_list/test_list.txt" + TRAIN_FILE_LIST: "./dataset/mini_pet/file_list/train_list.txt" + VAL_FILE_LIST: "./dataset/mini_pet/file_list/val_list.txt" + VIS_FILE_LIST: "./dataset/mini_pet/file_list/test_list.txt" + IGNORE_INDEX: 255 + SEPARATOR: " " +FREEZE: + MODEL_FILENAME: "__model__" + PARAMS_FILENAME: "__params__" +MODEL: + MODEL_NAME: "icnet" + DEFAULT_NORM_TYPE: "bn" + MULTI_LOSS_WEIGHT: "[1.0, 0.4, 0.16]" + ICNET: + DEPTH_MULTIPLIER: 0.5 +TRAIN: + PRETRAINED_MODEL_DIR: "./pretrained_model/icnet_bn_cityscapes/" + MODEL_SAVE_DIR: "./saved_model/icnet_pet/" + SNAPSHOT_EPOCH: 10 +TEST: + TEST_MODEL: "./saved_model/icnet_pet/final" +SOLVER: + NUM_EPOCHS: 100 + LR: 0.005 + LR_POLICY: "poly" + OPTIMIZER: "sgd" diff --git a/configs/cityscape.yaml b/configs/pspnet.yaml similarity index 60% rename from configs/cityscape.yaml rename to configs/pspnet.yaml index 0650d58a068e19c6cfe36f2d01c8e37dd5935045..fdc960d6af81bcba30128e972f260da05b33b0e8 100644 --- a/configs/cityscape.yaml +++ b/configs/pspnet.yaml @@ -1,5 +1,5 @@ EVAL_CROP_SIZE: (2049, 1025) # (width, height), for unpadding rangescaling and stepscaling -TRAIN_CROP_SIZE: (769, 769) # (width, height), for unpadding rangescaling and stepscaling +TRAIN_CROP_SIZE: (713, 713) # (width, height), for unpadding rangescaling and stepscaling AUG: AUG_METHOD: "stepscaling" # choice unpadding rangescaling and stepscaling FIX_RESIZE_SIZE: (640, 640) # (width, height), for unpadding @@ -10,18 +10,6 @@ AUG: MIN_SCALE_FACTOR: 0.5 # for stepscaling SCALE_STEP_SIZE: 0.25 # for stepscaling MIRROR: True - RICH_CROP: - ENABLE: False - ASPECT_RATIO: 0.33 - BLUR: True - BLUR_RATIO: 0.1 - FLIP: True - FLIP_RATIO: 0.2 - MAX_ROTATION: 15 - MIN_AREA_RATIO: 0.5 - BRIGHTNESS_JITTER_RATIO: 0.5 - CONTRAST_JITTER_RATIO: 0.5 - SATURATION_JITTER_RATIO: 0.5 BATCH_SIZE: 4 DATASET: DATA_DIR: "./dataset/cityscapes/" @@ -35,17 +23,16 @@ FREEZE: MODEL_FILENAME: "model" PARAMS_FILENAME: "params" MODEL: - DEFAULT_NORM_TYPE: "gn" - MODEL_NAME: "deeplabv3p" - DEEPLAB: - ASPP_WITH_SEP_CONV: True - DECODER_USE_SEP_CONV: True + MODEL_NAME: "pspnet" + DEFAULT_NORM_TYPE: "bn" + PSPNET: + DEPTH_MULTIPLIER: 1 + LAYERS: 50 TEST: - TEST_MODEL: "snapshots/cityscape_v5/final/" + TEST_MODEL: "snapshots/cityscapes_pspnet50/final" TRAIN: - MODEL_SAVE_DIR: "snapshots/cityscape_v7/" - PRETRAINED_MODEL: u"pretrain/deeplabv3plus_gn_init" - RESUME: False + MODEL_SAVE_DIR: "snapshots/cityscapes_pspnet50/" + PRETRAINED_MODEL_DIR: u"pretrained_model/pspnet50_bn_cityscapes/" SNAPSHOT_EPOCH: 10 SOLVER: LR: 0.001 diff --git a/configs/unet_pet.yaml b/configs/unet_pet.yaml index 23bd68d5918fe89c3771cdc2e46871918b54e29c..2f3cc50e7e99ea7b8ff749d57f8319aa6b212a6f 100644 --- a/configs/unet_pet.yaml +++ b/configs/unet_pet.yaml @@ -12,18 +12,6 @@ AUG: MIN_SCALE_FACTOR: 0.75 # for stepscaling SCALE_STEP_SIZE: 0.25 # for stepscaling MIRROR: True - RICH_CROP: - ENABLE: False - ASPECT_RATIO: 0.33 - BLUR: True - BLUR_RATIO: 0.1 - FLIP: True - FLIP_RATIO: 0.2 - MAX_ROTATION: 15 - MIN_AREA_RATIO: 0.5 - BRIGHTNESS_JITTER_RATIO: 0.5 - CONTRAST_JITTER_RATIO: 0.5 - SATURATION_JITTER_RATIO: 0.5 BATCH_SIZE: 4 DATASET: DATA_DIR: "./dataset/mini_pet/" @@ -45,8 +33,7 @@ TEST: TEST_MODEL: "./test/saved_model/unet_pet/final/" TRAIN: MODEL_SAVE_DIR: "./test/saved_models/unet_pet/" - PRETRAINED_MODEL: "./test/models/unet_coco/" - RESUME: False + PRETRAINED_MODEL_DIR: "./test/models/unet_coco/" SNAPSHOT_EPOCH: 10 SOLVER: NUM_EPOCHS: 500 diff --git a/docs/annotation/README.md b/docs/annotation/README.md index 13a98e823eef195cef2acc457e7fa6df41bb9834..5be98ce7841af87c7a8f65e708c02aa9b08dc907 100644 --- a/docs/annotation/README.md +++ b/docs/annotation/README.md @@ -1,97 +1,12 @@ # PaddleSeg 数据标注 -用户需预先采集好用于训练、评估和测试的图片,并使用数据标注工具[LabelMe](https://github.com/wkentaro/labelme)完成数据标注,最后用我们提供的数据转换脚本将LabelMe产出的数据格式转换为模型训练时所需的数据格式。 +用户需预先采集好用于训练、评估和测试的图片,并使用数据标注工具完成数据标注。 -## 1 LabelMe的安装 +PaddleSeg支持2种标注工具:LabelMe、精灵数据标注工具。 -用户在采集完用于训练、评估和预测的图片之后,需使用数据标注工具[LabelMe](https://github.com/wkentaro/labelme)完成数据标注。LabelMe支持在Windows/macOS/Linux三个系统上使用,且三个系统下的标注格式是一样。具体的安装流程请参见[官方安装指南](https://github.com/wkentaro/labelme)。 +标注教程如下: +- [LabelMe标注教程](labelme2seg.md) +- [精灵数据标注工具教程](jingling2seg.md) -## 2 LabelMe的使用 +最后用我们提供的数据转换脚本将上述标注工具产出的数据格式转换为模型训练时所需的数据格式。 -打开终端输入`labelme`会出现LableMe的交互界面,可以先预览`LabelMe`给出的已标注好的图片,再开始标注自定义数据集。 - -
- -

图1 LableMe交互界面的示意图

-
- -* 预览已标注图片 - -获取`LabelMe`的源码: -``` -git clone https://github.com/wkentaro/labelme -``` -终端输入`labelme`会出现LableMe的交互界面,点击`OpenDir`打开`/examples/semantic_segmentation/data_annotated`,其中``为克隆下来的`labelme`的路径,打开后示意的是语义分割的真值标注。 - -
- -

图2 已标注图片的示意图

-
- -* 开始标注 - -请按照下述步骤标注数据集: - -​ (1) 点击`OpenDir`打开待标注图片所在目录,点击`Create Polygons`,沿着目标的边缘画多边形,完成后输入目标的类别。在标注过程中,如果某个点画错了,可以按撤销快捷键可撤销该点。Mac下的撤销快捷键为`command+Z`。 - -
- -

图3 标注单个目标的示意图

-
- -​ (2) 右击选择`Edit Polygons`可以整体移动多边形的位置,也可以移动某个点的位置;右击选择`Edit Label`可以修改每个目标的类别。请根据自己的需要执行这一步骤,若不需要修改,可跳过。 - -
- - -

图4 修改标注的示意图

-
- -​ (3) 图片中所有目标的标注都完成后,点击`Save`保存json文件,**请将json文件和图片放在同一个文件夹里**,点击`Next Image`标注下一张图片。 - -LableMe产出的真值文件可参考我们给出的文件夹`data_annotated`。 - -
- -

图5 LableMe产出的真值文件的示意图

-
- - ## 3 数据格式转换 - -* 我们用于完成语义分割的数据集目录结构如下: - - ``` - my_dataset # 根目录 - |-- JPEGImages # 数据集图片 - |-- SegmentationClassPNG # 数据集真值 - | |-- xxx.png # 像素级别的真值信息 - | |... - |-- class_names.txt # 数据集的类别名称 - - ``` - -
- -

图6 训练所需的数据集目录的结构示意图

-
- -* 运行转换脚本需要依赖labelme和pillow,如未安装,请先安装。Labelme的具体安装流程请参见[官方安装指南](https://github.com/wkentaro/labelme)。Pillow的安装: - -```shell -pip install pillow -``` - -* 运行以下代码,将标注后的数据转换成满足以上格式的数据集: - -``` - python labelme2seg.py -``` - -其中,``为图片以及LabelMe产出的json文件所在文件夹的目录,``为转换后的数据集所在文件夹的目录。**需注意的是:``不用预先创建,脚本运行时会自动创建,否则会报错。** - -转换得到的数据集可参考我们给出的文件夹`my_dataset`。其中,文件`class_names.txt`是数据集中所有标注类别的名称,包含背景类;文件夹`JPEGImages`保存的是数据集的图片;文件夹`SegmentationClassPNG`保存的是各图片的像素级别的真值信息,背景类`_background_`对应为0,其它目标类别从1开始递增,至多为255。 - -
- -

图7 训练所需的数据集各目录的内容示意图

-
diff --git a/docs/annotation/data_annotated/aa63d7e6db0d03137883772c246c6761fc201059.jpg b/docs/annotation/data_annotated/aa63d7e6db0d03137883772c246c6761fc201059.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3d10c0d1ea47987153f7c51e6b992d1dfe35d3ae Binary files /dev/null and b/docs/annotation/data_annotated/aa63d7e6db0d03137883772c246c6761fc201059.jpg differ diff --git a/docs/annotation/data_annotated/aa63d7e6db0d03137883772c246c6761fc201059.json b/docs/annotation/data_annotated/aa63d7e6db0d03137883772c246c6761fc201059.json new file mode 100644 index 0000000000000000000000000000000000000000..34bb4674f0d0f16f257e2cc0abb7292f1dc4566d --- /dev/null +++ b/docs/annotation/data_annotated/aa63d7e6db0d03137883772c246c6761fc201059.json @@ -0,0 +1 @@ +{"path":"/Users/chulutao/dataset/humanseg/aa63d7e6db0d03137883772c246c6761fc201059.jpg","outputs":{"object":[{"name":"person","polygon":{"x1":321.99,"y1":63,"x2":293,"y2":98.00999999999999,"x3":245.01,"y3":141.01,"x4":221,"y4":194,"x5":231.99,"y5":237,"x6":231.99,"y6":348.01,"x7":191,"y7":429,"x8":197,"y8":465.01,"x9":193,"y9":586,"x10":151,"y10":618.01,"x11":124,"y11":622,"x12":100,"y12":703,"x13":121.99,"y13":744,"x14":141.99,"y14":724,"x15":163,"y15":658.01,"x16":238.01,"y16":646,"x17":259,"y17":627,"x18":313,"y18":618.01,"x19":416,"y19":639,"x20":464,"y20":606,"x21":454,"y21":555.01,"x22":404,"y22":508.01,"x23":430,"y23":489,"x24":407,"y24":464,"x25":397,"y25":365.01,"x26":407,"y26":290,"x27":361.99,"y27":252,"x28":376,"y28":215.01,"x29":391.99,"y29":189,"x30":388.01,"y30":135.01,"x31":340,"y31":120,"x32":313,"y32":161.01,"x33":307,"y33":188.01,"x34":311,"y34":207,"x35":277,"y35":186,"x36":293,"y36":137,"x37":308.01,"y37":117,"x38":361,"y38":93}}]},"time_labeled":1568101256852,"labeled":true,"size":{"width":706,"height":1000,"depth":3}} \ No newline at end of file diff --git a/docs/annotation/jingling2seg.md b/docs/annotation/jingling2seg.md new file mode 100644 index 0000000000000000000000000000000000000000..127bfb693f46c4391634e91df702a2d961cae85d --- /dev/null +++ b/docs/annotation/jingling2seg.md @@ -0,0 +1,94 @@ +# 精灵标注工具教程 + +## 1 精灵标注工具的安装 + +用户在采集完用于训练、评估和预测的图片之后,可使用[精灵数据标注工具](http://www.jinglingbiaozhu.com/)完成数据标注。精灵标注支持在Windows/macOS/Linux三个系统上使用,Mac的话可以到MacStore中搜索colabeler下载即可。 + +## 2 精灵标注工具的使用 + +开始标注自定义数据集之前,可以先预览精灵标注官网的[文字教程](http://www.jinglingbiaozhu.com/?type=tutorial&cat_id=4)和[视频教程](http://www.jinglingbiaozhu.com/?type=tutorial&cat_id=5)。 + + +* 开始标注 + +打开精灵标注工具。 + +
+ +

图1 精灵标注交互界面的示意图

+
+ +请按照下述步骤标注数据集: + +(1) 点击`新建`,然后选择`位置标注`,选择`图片文件夹`,修改填写所需的`分类值`(注意:以英文逗号隔开),点击`创建`按钮,软件会自动加载文件夹下的图片(png,jpg,gif)并创建一个项目。 + +位置标注支持三种类型:矩形,多边形和曲线。选择简单好用的`多边形框`,沿着目标的边缘画多边形,完成后在右侧输入目标的类别。 + +**注意:切记单张图片标注完成后进行保存,点击下方中央的勾按钮或者使用快捷键ctrl+s**。 + +然后可以点击左边的前一个后一个或者直接使用键盘的向左按钮和向右按钮来切换图片。 + +
+ +

图2 标注单个目标的示意图

+
+ +(2) 单击目标框,鼠标拖动可以整体移动多边形的位置;点击左侧的`删除选框`可以删除画错的目标框;点击右侧的`标注信息`可修改目标类别。请根据自己的需要执行这一步骤,若不需要修改,可跳过。 + +
+ +

图3 修改标注的示意图

+
+ +(3) 当所有图片的标注都完成后,点击左侧的`导出`,输出方式选择`JSON`,指定`保存位置`,点击`确定导出`保存所有图片的标注文件。 + +**注意:导出的标注文件位于`保存位置`下的`outputs`目录。** + +精灵标注产出的真值文件可参考我们给出的文件夹`data_annotated`。 + +
+ +

图4 精灵标注产出的真值文件的示意图

+
+ + ## 3 数据格式转换 + +* 我们用于完成语义分割的数据集目录结构如下: + + ``` + my_dataset # 根目录 + |-- JPEGImages # 数据集图片 + |-- SegmentationClassPNG # 数据集真值 + | |-- xxx.png # 像素级别的真值信息 + | |... + |-- class_names.txt # 数据集的类别名称 + + ``` + +
+ +

图5 训练所需的数据集目录的结构示意图

+
+ +* 运行转换脚本需要依赖labelme和pillow,如未安装,请先安装。Labelme的具体安装流程请参见[官方安装指南](https://github.com/wkentaro/labelme)。Pillow的安装: + +```shell +pip install pillow +``` + +* 运行以下代码,将标注后的数据转换成满足以上格式的数据集: + +``` + python jingling2seg.py +``` + +其中,``为精灵标注产出的json文件所在文件夹的目录,一般为精灵工具使用(3)中`保存位置`下的`outputs`目录。``为转换后的数据集所在文件夹的目录。 + +**注意:``不用预先创建,脚本运行时会自动创建,否则会报错。** + +转换得到的数据集可参考我们给出的文件夹`my_dataset`。其中,文件`class_names.txt`是数据集中所有标注类别的名称,包含背景类;文件夹`JPEGImages`保存的是数据集的图片;文件夹`SegmentationClassPNG`保存的是各图片的像素级别的真值信息,背景类`_background_`对应为0,其它目标类别从1开始递增,至多为255。 + +
+ +

图6 训练所需的数据集各目录的内容示意图

+
diff --git a/docs/annotation/jingling2seg.py b/docs/annotation/jingling2seg.py new file mode 100644 index 0000000000000000000000000000000000000000..18626157738671afc8415471d108e9d6a04f8495 --- /dev/null +++ b/docs/annotation/jingling2seg.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python + +from __future__ import print_function + +import argparse +import glob +import json +import os +import os.path as osp +import sys + +import numpy as np +import PIL.Image + +import labelme + + +def main(): + parser = argparse.ArgumentParser( + formatter_class=argparse.ArgumentDefaultsHelpFormatter + ) + parser.add_argument('label_dir', help='input annotated directory') + parser.add_argument('output_dir', help='output dataset directory') + args = parser.parse_args() + + if osp.exists(args.output_dir): + print('Output directory already exists:', args.output_dir) + sys.exit(1) + + os.makedirs(args.output_dir) + os.makedirs(osp.join(args.output_dir, 'JPEGImages')) + os.makedirs(osp.join(args.output_dir, 'SegmentationClassPNG')) + print('Creating dataset:', args.output_dir) + + # get the all class names for the given dataset + class_names = ['_background_'] + for label_file in glob.glob(osp.join(args.label_dir, '*.json')): + with open(label_file) as f: + data = json.load(f) + if data['outputs']: + for output in data['outputs']['object']: + name = output['name'] + cls_name = name + if not cls_name in class_names: + class_names.append(cls_name) + + class_name_to_id = {} + for i, class_name in enumerate(class_names): + class_id = i # starts with 0 + class_name_to_id[class_name] = class_id + if class_id == 0: + assert class_name == '_background_' + class_names = tuple(class_names) + print('class_names:', class_names) + + out_class_names_file = osp.join(args.output_dir, 'class_names.txt') + with open(out_class_names_file, 'w') as f: + f.writelines('\n'.join(class_names)) + print('Saved class_names:', out_class_names_file) + + for label_file in glob.glob(osp.join(args.label_dir, '*.json')): + print('Generating dataset from:', label_file) + with open(label_file) as f: + base = osp.splitext(osp.basename(label_file))[0] + out_img_file = osp.join( + args.output_dir, 'JPEGImages', base + '.jpg') + out_png_file = osp.join( + args.output_dir, 'SegmentationClassPNG', base + '.png') + + data = json.load(f) + + data_shapes = [] + if data['outputs']: + for output in data['outputs']['object']: + if 'polygon' in output.keys(): + polygon = output['polygon'] + name = output['name'] + + # convert jingling format to labelme format + points = [] + for i in range(1, int(len(polygon) / 2) + 1): + points.append([polygon['x' + str(i)], polygon['y' + str(i)]]) + shape = {'label': name, 'points': points, 'shape_type': 'polygon'} + data_shapes.append(shape) + + img_file = osp.join(osp.dirname(label_file), data['path']) + img = np.asarray(PIL.Image.open(img_file)) + PIL.Image.fromarray(img).save(out_img_file) + + lbl = labelme.utils.shapes_to_label( + img_shape=img.shape, + shapes=data_shapes, + label_name_to_value=class_name_to_id, + ) + + if osp.splitext(out_png_file)[1] != '.png': + out_png_file += '.png' + # Assume label ranses [0, 255] for uint8, + if lbl.min() >= 0 and lbl.max() <= 255: + lbl_pil = PIL.Image.fromarray(lbl.astype(np.uint8), mode='L') + lbl_pil.save(out_png_file) + else: + raise ValueError( + '[%s] Cannot save the pixel-wise class label as PNG. ' + 'Please consider using the .npy format.' % out_png_file + ) + + +if __name__ == '__main__': + main() diff --git a/docs/annotation/labelme2seg.md b/docs/annotation/labelme2seg.md new file mode 100644 index 0000000000000000000000000000000000000000..b969ea092c1b5e9dddf4a8dc27255cb7818c9571 --- /dev/null +++ b/docs/annotation/labelme2seg.md @@ -0,0 +1,95 @@ +# LabelMe数据标注教程 + +## 1 LabelMe的安装 + +用户在采集完用于训练、评估和预测的图片之后,需使用数据标注工具[LabelMe](https://github.com/wkentaro/labelme)完成数据标注。LabelMe支持在Windows/macOS/Linux三个系统上使用,且三个系统下的标注格式是一样。具体的安装流程请参见[官方安装指南](https://github.com/wkentaro/labelme)。 + +## 2 LabelMe的使用 + +打开终端输入`labelme`会出现LableMe的交互界面,可以先预览`LabelMe`给出的已标注好的图片,再开始标注自定义数据集。 + +
+ +

图1 LableMe交互界面的示意图

+
+ +* 预览已标注图片 + +获取`LabelMe`的源码: +``` +git clone https://github.com/wkentaro/labelme +``` +终端输入`labelme`会出现LableMe的交互界面,点击`OpenDir`打开`/examples/semantic_segmentation/data_annotated`,其中``为克隆下来的`labelme`的路径,打开后示意的是语义分割的真值标注。 + +
+ +

图2 已标注图片的示意图

+
+ +* 开始标注 + +请按照下述步骤标注数据集: + +​ (1) 点击`OpenDir`打开待标注图片所在目录,点击`Create Polygons`,沿着目标的边缘画多边形,完成后输入目标的类别。在标注过程中,如果某个点画错了,可以按撤销快捷键可撤销该点。Mac下的撤销快捷键为`command+Z`。 + +
+ +

图3 标注单个目标的示意图

+
+ +​ (2) 右击选择`Edit Polygons`可以整体移动多边形的位置,也可以移动某个点的位置;右击选择`Edit Label`可以修改每个目标的类别。请根据自己的需要执行这一步骤,若不需要修改,可跳过。 + +
+ + +

图4 修改标注的示意图

+
+ +​ (3) 图片中所有目标的标注都完成后,点击`Save`保存json文件,**请将json文件和图片放在同一个文件夹里**,点击`Next Image`标注下一张图片。 + +LableMe产出的真值文件可参考我们给出的文件夹`data_annotated`。 + +
+ +

图5 LableMe产出的真值文件的示意图

+
+ + ## 3 数据格式转换 + +* 我们用于完成语义分割的数据集目录结构如下: + + ``` + my_dataset # 根目录 + |-- JPEGImages # 数据集图片 + |-- SegmentationClassPNG # 数据集真值 + | |-- xxx.png # 像素级别的真值信息 + | |... + |-- class_names.txt # 数据集的类别名称 + + ``` + +
+ +

图6 训练所需的数据集目录的结构示意图

+
+ +* 运行转换脚本需要依赖labelme和pillow,如未安装,请先安装。Labelme的具体安装流程请参见[官方安装指南](https://github.com/wkentaro/labelme)。Pillow的安装: + +```shell +pip install pillow +``` + +* 运行以下代码,将标注后的数据转换成满足以上格式的数据集: + +``` + python labelme2seg.py +``` + +其中,``为图片以及LabelMe产出的json文件所在文件夹的目录,``为转换后的数据集所在文件夹的目录。**需注意的是:``不用预先创建,脚本运行时会自动创建,否则会报错。** + +转换得到的数据集可参考我们给出的文件夹`my_dataset`。其中,文件`class_names.txt`是数据集中所有标注类别的名称,包含背景类;文件夹`JPEGImages`保存的是数据集的图片;文件夹`SegmentationClassPNG`保存的是各图片的像素级别的真值信息,背景类`_background_`对应为0,其它目标类别从1开始递增,至多为255。 + +
+ +

图7 训练所需的数据集各目录的内容示意图

+
diff --git a/docs/check.md b/docs/check.md new file mode 100644 index 0000000000000000000000000000000000000000..c47618b67cbfb2de2bb90758cdd566aaea956310 --- /dev/null +++ b/docs/check.md @@ -0,0 +1,55 @@ +# 配置/数据校验 +对用户自定义的数据集和yaml配置进行校验,帮助用户排查基本的数据和配置问题。 + +数据校验脚本如下,支持通过`YAML_FILE_PATH`来指定配置文件。 +``` +# YAML_FILE_PATH为yaml配置文件路径 +python pdseg/check.py --cfg ${YAML_FILE_PATH} +``` +运行后,命令行将显示校验结果的概览信息,详细信息可到detail.log文件中查看。 + +### 1 列表分割符校验 +判断在`TRAIN_FILE_LIST`,`VAL_FILE_LIST`和`TEST_FILE_LIST`列表文件中的分隔符`DATASET.SEPARATOR`设置是否正确。 +### 2 数据集读取校验 +通过是否能成功读取`DATASET.TRAIN_FILE_LIST`,`DATASET.VAL_FILE_LIST`,`DATASET.TEST_FILE_LIST`中所有图片,判断这3项设置是否正确。 + +若不正确返回错误信息。错误可能有多种情况,如数据集路径设置错误、图片损坏等。 + +### 3 标注格式校验 +检查标注图像是否为PNG格式。 + +**NOTE:** 标注图像请使用PNG无损压缩格式的图片,若使用其他格式则可能影响精度。 + +### 4 标注通道数校验 +检查标注图的通道数。正确的标注图应该为单通道图像。 + +### 5 标注类别校验 +检查实际标注类别是否和配置参数`DATASET.NUM_CLASSES`,`DATASET.IGNORE_INDEX`匹配。 + +**NOTE:** +标注图像类别数值必须在[0~(`DATASET.NUM_CLASSES`-1)]范围内或者为`DATASET.IGNORE_INDEX`。 +标注类别最好从0开始,否则可能影响精度。 + +### 6 标注像素统计 +统计每种类别像素数量,显示以供参考。 + +### 7 图像格式校验 +检查图片类型`DATASET.IMAGE_TYPE`是否设置正确。 + +**NOTE:** 当数据集包含三通道图片时`DATASET.IMAGE_TYPE`设置为rgb; +当数据集全部为四通道图片时`DATASET.IMAGE_TYPE`设置为rgba; + +### 8 图像与标注图尺寸一致性校验 +验证图像尺寸和对应标注图尺寸是否一致。 + +### 9 模型验证参数`EVAL_CROP_SIZE`校验 +验证`EVAL_CROP_SIZE`是否设置正确,共有3种情形: + +- 当`AUG.AUG_METHOD`为unpadding时,`EVAL_CROP_SIZE`的宽高应不小于`AUG.FIX_RESIZE_SIZE`的宽高。 + +- 当`AUG.AUG_METHOD`为stepscaling时,`EVAL_CROP_SIZE`的宽高应不小于原图中最大的宽高。 + +- 当`AUG.AUG_METHOD`为rangscaling时,`EVAL_CROP_SIZE`的宽高应不小于缩放后图像中最大的宽高。 + +### 10 数据增强参数`AUG.INF_RESIZE_VALUE`校验 +验证`AUG.INF_RESIZE_VALUE`是否在[`AUG.MIN_RESIZE_VALUE`~`AUG.MAX_RESIZE_VALUE`]范围内。若在范围内,则通过校验。 diff --git a/docs/configs/basic_group.md b/docs/configs/basic_group.md index 24bdbe39c43f6dc2f8d7f56d9d18ed360c3e404f..c66752f38e153084601c89e0aeb0c9385f02885b 100644 --- a/docs/configs/basic_group.md +++ b/docs/configs/basic_group.md @@ -8,7 +8,7 @@ BASIC Group存放所有通用配置 ### 默认值 -[104.008, 116.669, 122.675] +[0.5, 0.5, 0.5]

@@ -19,7 +19,7 @@ BASIC Group存放所有通用配置 ### 默认值 -[1.000, 1.000, 1.000] +[0.5, 0.5, 0.5]

@@ -65,5 +65,7 @@ BASIC Group存放所有通用配置 * 增大BATCH_SIZE有利于模型训练时的收敛速度,但是会带来显存的开销。请根据实际情况评估后填写合适的值 +* 目前PaddleSeg提供的很多预训练模型都有BN层,如果BATCH SIZE设置为1,则此时训练可能不稳定导致nan +

diff --git a/docs/configs/train_group.md b/docs/configs/train_group.md index 3c7c0fbb6efc04d232bbe3ba54275cb91bac699b..6c8a0d79c79af665d8c7bf54a2b7555aa024bb8d 100644 --- a/docs/configs/train_group.md +++ b/docs/configs/train_group.md @@ -11,7 +11,7 @@ TRAIN Group存放所有和训练相关的配置

-## `PRETRAINED_MODEL` +## `PRETRAINED_MODEL_DIR` 预训练模型路径 ## 默认值 @@ -28,19 +28,15 @@ TRAIN Group存放所有和训练相关的配置

-## `RESUME` -是否从预训练模型中恢复参数并继续训练 +## `RESUME_MODEL_DIR` +从指定路径中恢复参数并继续训练 ## 默认值 -False +无 ## 注意事项 -* 当该字段被置为True且`PRETRAINED_MODEL`不存在时,该选项不生效 - -* 当该字段被置为True且`PRETRAINED_MODEL`存在时,PaddleSeg会恢复到上一次训练的最近一个epoch,并且恢复训练过程中的临时变量(如已经衰减过的学习率,Optimizer的动量数据等) - -* 当该字段被置为True且`PRETRAINED_MODEL`存在时,`PRETRAINED_MODEL`路径的最后一个目录必须为int数值或者字符串final,PaddleSeg会将int数值作为当前起始EPOCH继续训练,若目录为final,则不会继续训练。若目录不满足上述条件,PaddleSeg会抛出错误。 +* 当`RESUME_MODEL_DIR`存在时,PaddleSeg会恢复到上一次训练的最近一个epoch,并且恢复训练过程中的临时变量(如已经衰减过的学习率,Optimizer的动量数据等),`PRETRAINED_MODEL`路径的最后一个目录必须为int数值或者字符串final,PaddleSeg会将int数值作为当前起始EPOCH继续训练,若目录为final,则不会继续训练。若目录不满足上述条件,PaddleSeg会抛出错误。

@@ -57,4 +53,4 @@ False * 仅在GPU多卡训练时该开关有效(Windows不支持多卡训练,因此无需打开该开关) -* GPU多卡训练时,建议开启该开关,可以提升模型的训练效果 \ No newline at end of file +* GPU多卡训练时,建议开启该开关,可以提升模型的训练效果 diff --git a/docs/data_aug.md b/docs/data_aug.md index 8d084b89e1b1e754320e9e0d6b508edea82835fe..2865d413b7090f414eb44c0681562837de21f19a 100644 --- a/docs/data_aug.md +++ b/docs/data_aug.md @@ -5,26 +5,40 @@ ![](imgs/data_aug_flow.png) -## resize +## Resize -resize 步骤是指将输入图像按照某种规则先进行resize,PaddleSeg支持以下3种resize方式: +resize步骤是指将输入图像按照某种规则讲图片重新缩放到某一个尺寸,PaddleSeg支持以下3种resize方式: ![](imgs/aug_method.png) -- unpadding +- Un-padding 将输入图像直接resize到某一个固定大小下,送入到网络中间训练,对应参数为AUG.FIX_RESIZE_SIZE。预测时同样操作。 -- stepscaling +- Step-Scaling 将输入图像按照某一个比例resize,这个比例以某一个步长在一定范围内随机变动。设定最小比例参数为`AUG.MIN_SCALE_FACTOR`, 最大比例参数`AUG.MAX_SCALE_FACTOR`,步长参数为`AUG.SCALE_STEP_SIZE`。预测时不对输入图像做处理。 -- rangescaling +- Range-Scaling 固定长宽比resize,即图像长边对齐到某一个固定大小,短边随同样的比例变化。设定最小大小参数为`AUG.MIN_RESIZE_VALUE`,设定最大大小参数为`AUG.MAX_RESIZE_VALUE`。预测时需要将长边对齐到`AUG.INF_RESIZE_VALUE`所指定的大小,其中`AUG.INF_RESIZE_VALUE`在`AUG.MIN_RESIZE_VALUE`和`AUG.MAX_RESIZE_VALUE`范围内。 -rangescaling示意图如下: +Range-Scaling示意图如下: ![](imgs/rangescale.png) -## rich crop +## 图像翻转 + +PaddleSeg支持以下2种翻转方式: + +- 左右翻转(Mirror) +使用开关`AUG.MIRROR`,为True时该项功能开启,为False时该项功能关闭。 + +- 上下翻转(Flip) +使用开关`AUG.FLIP`,为True时该项功能开启,`AUG.FLIP_RATIO`控制是否上下翻转的概率。为False时该项功能关闭。 + +以上2种开关独立运作,可组合使用。故图像翻转一共有如下4种可能的情况: + + + +## Rich Crop Rich Crop是PaddleSeg结合实际业务经验开放的一套数据增强策略,面向标注数据少,测试数据情况繁杂的分割业务场景使用的数据增强策略。流程如下图所示: @@ -35,21 +49,16 @@ rich crop是指对图像进行多种变换,保证在训练过程中数据的 - blur 图像加模糊,使用开关`AUG.RICH_CROP.BLUR`,为False时该项功能关闭。`AUG.RICH_CROP.BLUR_RATIO`控制加入模糊的概率。 -- flip -图像上下翻转,使用开关`AUG.RICH_CROP.FLIP`,为False时该项功能关闭。`AUG.RICH_CROP.FLIP_RATIO`控制加入模糊的概率。 - - rotation 图像旋转,`AUG.RICH_CROP.MAX_ROTATION`控制最大旋转角度。旋转产生的多余的区域的填充值为均值。 - aspect - 图像长宽比调整,从图像中crop一定区域出来之后在某一长宽比内进行resize。控制参数`AUG.RICH_CROP.MIN_AREA_RATIO`和`AUG.RICH_CROP.ASPECT_RATIO`。 - color jitter - 图像颜色调整,控制参数`AUG.RICH_CROP.BRIGHTNESS_JITTER_RATIO`、`AUG.RICH_CROP.SATURATION_JITTER_RATIO`、`AUG.RICH_CROP.CONTRAST_JITTER_RATIO`。 -## random crop +## Random Crop 该步骤主要是通过crop的方式使得输入到网络中的图像在某一个固定大小,控制该大小的参数为TRAIN_CROP_SIZE,类型为tuple,格式为(width, height). 当输入图像大小小于CROP_SIZE的时候会对输入图像进行padding,padding值为均值。 diff --git a/docs/data_prepare.md b/docs/data_prepare.md index 1c371f2bbc398cf6498ee799218465b688a31fbc..13791dc5661e5e1393fda05469802e989d1e4d94 100644 --- a/docs/data_prepare.md +++ b/docs/data_prepare.md @@ -58,61 +58,3 @@ PaddleSeg采用通用的文件列表方式组织训练集、验证集和测试 ![cityscapes_filelist](./imgs/file_list.png) 完整的配置信息可以参考[`./dataset/cityscapes_demo`](../dataset/cityscapes_demo/)目录下的yaml和文件列表。 - -## 数据校验 -对用户自定义的数据集和yaml配置进行校验,帮助用户排查基本的数据和配置问题。 - -数据校验脚本如下,支持通过`YAML_FILE_PATH`来指定配置文件。 -``` -# YAML_FILE_PATH为yaml配置文件路径 -python pdseg/check.py --cfg ${YAML_FILE_PATH} -``` -运行后,命令行将显示校验结果的概览信息,详细信息可到detail.log文件中查看。 - -### 1 列表分割符校验 -判断在`TRAIN_FILE_LIST`,`VAL_FILE_LIST`和`TEST_FILE_LIST`列表文件中的分隔符`DATASET.SEPARATOR`设置是否正确。 -### 2 数据集读取校验 -通过是否能成功读取`DATASET.TRAIN_FILE_LIST`,`DATASET.VAL_FILE_LIST`,`DATASET.TEST_FILE_LIST`中所有图片,判断这3项设置是否正确。 - -若不正确返回错误信息。错误可能有多种情况,如数据集路径设置错误、图片损坏等。 - -### 3 标注格式校验 -检查标注图像是否为PNG格式。 - -**NOTE:** 标注图像请使用PNG无损压缩格式的图片,若使用其他格式则可能影响精度。 - -### 4 标注通道数校验 -检查标注图的通道数。正确的标注图应该为单通道图像。 - -### 5 标注类别校验 -检查实际标注类别是否和配置参数`DATASET.NUM_CLASSES`,`DATASET.IGNORE_INDEX`匹配。 - -**NOTE:** -标注图像类别数值必须在[0~(`DATASET.NUM_CLASSES`-1)]范围内或者为`DATASET.IGNORE_INDEX`。 -标注类别最好从0开始,否则可能影响精度。 - -### 6 标注像素统计 -统计每种类别像素数量,显示以供参考。 - -### 7 图像格式校验 -检查图片类型`DATASET.IMAGE_TYPE`是否设置正确。 - -**NOTE:** 当数据集包含三通道图片时`DATASET.IMAGE_TYPE`设置为rgb; -当数据集全部为四通道图片时`DATASET.IMAGE_TYPE`设置为rgba; - -### 8 图像与标注图尺寸一致性校验 -验证图像尺寸和对应标注图尺寸是否一致。 - -### 9 模型验证参数`EVAL_CROP_SIZE`校验 -验证`EVAL_CROP_SIZE`是否设置正确,共有3种情形: - -- 当`AUG.AUG_METHOD`为unpadding时,`EVAL_CROP_SIZE`的宽高应不小于`AUG.FIX_RESIZE_SIZE`的宽高。 - -- 当`AUG.AUG_METHOD`为stepscaling时,`EVAL_CROP_SIZE`的宽高应不小于原图中最大的宽高。 - -- 当`AUG.AUG_METHOD`为rangscaling时,`EVAL_CROP_SIZE`的宽高应不小于缩放后图像中最大的宽高。 - -我们将计算并给出`EVAL_CROP_SIZE`的建议值。 - -### 10 数据增强参数`AUG.INF_RESIZE_VALUE`校验 -验证`AUG.INF_RESIZE_VALUE`是否在[`AUG.MIN_RESIZE_VALUE`~`AUG.MAX_RESIZE_VALUE`]范围内。若在范围内,则通过校验。 diff --git a/docs/imgs/annotation/jingling-1.png b/docs/imgs/annotation/jingling-1.png new file mode 100644 index 0000000000000000000000000000000000000000..6c29de5858ce95be95b9c1ce3a6f01bde8cbe1eb Binary files /dev/null and b/docs/imgs/annotation/jingling-1.png differ diff --git a/docs/imgs/annotation/jingling-2.png b/docs/imgs/annotation/jingling-2.png new file mode 100644 index 0000000000000000000000000000000000000000..1e93e9491ac2667535b2dcc6016a1a9ac3b83f20 Binary files /dev/null and b/docs/imgs/annotation/jingling-2.png differ diff --git a/docs/imgs/annotation/jingling-3.png b/docs/imgs/annotation/jingling-3.png new file mode 100644 index 0000000000000000000000000000000000000000..bd0cba879b045e7c31b0ef024bbf75cc1ba3c9e3 Binary files /dev/null and b/docs/imgs/annotation/jingling-3.png differ diff --git a/docs/imgs/annotation/jingling-4.png b/docs/imgs/annotation/jingling-4.png new file mode 100644 index 0000000000000000000000000000000000000000..8a2e70b985cf4bf4cbb5ed5de88221e8a86aaf25 Binary files /dev/null and b/docs/imgs/annotation/jingling-4.png differ diff --git a/docs/imgs/annotation/jingling-5.png b/docs/imgs/annotation/jingling-5.png new file mode 100644 index 0000000000000000000000000000000000000000..54bfb1e03f89078873cae11704d6d6cc6eb7cd2c Binary files /dev/null and b/docs/imgs/annotation/jingling-5.png differ diff --git a/docs/imgs/data_aug_example.png b/docs/imgs/data_aug_example.png index 38c4e153b45658393594a4cd2db74a871ae684f5..841513c3ec6b8e00d733d8d02bafe1ac61e98c88 100644 Binary files a/docs/imgs/data_aug_example.png and b/docs/imgs/data_aug_example.png differ diff --git a/docs/imgs/data_aug_flip_mirror.png b/docs/imgs/data_aug_flip_mirror.png new file mode 100644 index 0000000000000000000000000000000000000000..9f51f0ef347cd44180f0c3dd03c92c42821886f2 Binary files /dev/null and b/docs/imgs/data_aug_flip_mirror.png differ diff --git a/docs/imgs/data_aug_flow.png b/docs/imgs/data_aug_flow.png index d087057bb242bbbdd37e7245dd673051b6175125..b9e0a32b7ed61da5a1bd8c94a8761f181898803c 100644 Binary files a/docs/imgs/data_aug_flow.png and b/docs/imgs/data_aug_flow.png differ diff --git a/docs/imgs/qq_group2.png b/docs/imgs/qq_group2.png new file mode 100644 index 0000000000000000000000000000000000000000..b28e0c30600d5dcfc513ab648071ca01d12080a8 Binary files /dev/null and b/docs/imgs/qq_group2.png differ diff --git a/docs/installation.md b/docs/installation.md index 7d738e08ba85adc33a46e1977d3d0cd23b55b266..751a0f77bb42d885c798dcd676764dda3bcb3bcd 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -2,18 +2,18 @@ ## 推荐开发环境 -* Python2.7 or 3.5+ +* Python 2.7 or 3.5+ * CUDA 9.2 -* cudnn v7.1 -* paddlepaddle >= 1.5.2 -* nccl >= 2.4.7 +* NVIDIA cuDNN v7.1 +* PaddlePaddle >= 1.5.2 +* 如果有多卡训练需求,请安装 NVIDIA NCCL >= 2.4.7,并在Linux环境下运行 ## 1. 安装PaddlePaddle ### pip安装 -由于图像分割任务模型计算量大,强烈推荐在GPU版本的paddlepaddle下使用PaddleSeg. +由于图像分割模型计算开销大,推荐在GPU版本的PaddlePaddle下使用PaddleSeg. ``` pip install paddlepaddle-gpu diff --git a/docs/model_export.md b/docs/model_export.md new file mode 100644 index 0000000000000000000000000000000000000000..eab31fddb4c590403726b504c340ae0155bd952b --- /dev/null +++ b/docs/model_export.md @@ -0,0 +1,21 @@ +# 模型导出 + +通过训练得到一个满足要求的模型后,如果想要将该模型接入到C++预测库或者Serving服务,我们需要通过`pdseg/export_model.py`来导出该模型。 + +该脚本的使用方法和`train.py/eval.py/vis.py`完全一样 + +## FLAGS + +|FLAG|用途|默认值|备注| +|-|-|-|-| +|--cfg|配置文件路径|None|| + +## 使用示例 + +我们使用[训练/评估/可视化](./usage.md)一节中训练得到的模型进行试用,脚本如下 + +```shell +python pdseg/export_model.py --cfg configs/unet_pet.yaml TEST.TEST_MODEL test/saved_models/unet_pet/final +``` + +预测模型会导出到`freeze_model`目录,用于C++预测的模型配置会导出到`freeze_model/deploy.yaml`下 diff --git a/docs/model_zoo.md b/docs/model_zoo.md index 03f61ade79b69cfd9f57d7ed8ece5ae874c1d196..612f74e6629870b96e7dbdf1f514958a34a4bd25 100644 --- a/docs/model_zoo.md +++ b/docs/model_zoo.md @@ -1,44 +1,45 @@ # PaddleSeg 预训练模型 -PaddleSeg对所有内置的分割模型都提供了公开数据集的下的预训练模型,通过加载预训练模型后训练可以在自定义数据集中得到更稳定地效果。 +PaddleSeg对所有内置的分割模型都提供了公开数据集下的预训练模型,通过加载预训练模型后训练可以在自定义数据集中得到更稳定地效果。 ## ImageNet预训练模型 -所有Imagenet预训练模型来自于PaddlePaddle图像分类库,想获取更多细节请点击[这里](https://github.com/PaddlePaddle/models/tree/develop/PaddleCV/image_classification)) +所有Imagenet预训练模型来自于PaddlePaddle图像分类库,想获取更多细节请点击[这里](https://github.com/PaddlePaddle/models/tree/develop/PaddleCV/image_classification) -| 模型 | 数据集合 | Depth multiplier | 模型加载config设置 | 下载地址 | Accuray Top1/5 Error| -|---|---|---|---|---|---| -| MobieNetV2_1.0x | ImageNet | 1.0x | MODEL.MODEL_NAME: deeplabv3p
MODEL.DEEPLAB.BACKBONE: mobilenet
MODEL.DEEPLAB.DEPTH_MULTIPLIER: 1.0
MODEL.DEFAULT_NORM_TYPE: bn| [MobileNetV2_1.0x](https://paddle-imagenet-models-name.bj.bcebos.com/MobileNetV2_pretrained.tar) | 72.15%/90.65% | -| MobieNetV2_0.25x | ImageNet | 0.25x | MODEL.MODEL_NAME: deeplabv3p
MODEL.DEEPLAB.BACKBONE: mobilenet
MODEL.DEEPLAB.DEPTH_MULTIPLIER: 0.25
MODEL.DEFAULT_NORM_TYPE: bn |[MobileNetV2_0.25x](https://paddle-imagenet-models-name.bj.bcebos.com/MobileNetV2_x0_25_pretrained.tar) | 53.21%/76.52% | -| MobieNetV2_0.5x | ImageNet | 0.5x | MODEL.MODEL_NAME: deeplabv3p
MODEL.DEEPLAB.BACKBONE: mobilenet
MODEL.DEEPLAB.DEPTH_MULTIPLIER: 0.5
MODEL.DEFAULT_NORM_TYPE: bn | [MobileNetV2_0.5x](https://paddle-imagenet-models-name.bj.bcebos.com/MobileNetV2_x0_5_pretrained.tar) | 65.03%/85.72% | -| MobieNetV2_1.5x | ImageNet | 1.5x | MODEL.MODEL_NAME: deeplabv3p
MODEL.DEEPLAB.BACKBONE: mobilenet
MODEL.DEEPLAB.DEPTH_MULTIPLIER: 1.5
MODEL.DEFAULT_NORM_TYPE: bn| [MobileNetV2_1.5x](https://paddle-imagenet-models-name.bj.bcebos.com/MobileNetV2_x1_5_pretrained.tar) | 74.12%/91.67% | -| MobieNetV2_2.0x | ImageNet | 2.0x | MODEL.MODEL_NAME: deeplabv3p
MODEL.DEEPLAB.BACKBONE: mobilenet
MODEL.DEEPLAB.DEPTH_MULTIPLIER: 2.0
MODEL.DEFAULT_NORM_TYPE: bn | [MobileNetV2_2.0x](https://paddle-imagenet-models-name.bj.bcebos.com/MobileNetV2_x2_0_pretrained.tar) | 75.23%/92.58% | +| 模型 | 数据集合 | Depth multiplier | 下载地址 | Accuray Top1/5 Error| +|---|---|---|---|---| +| MobieNetV2_1.0x | ImageNet | 1.0x | [MobileNetV2_1.0x](https://paddle-imagenet-models-name.bj.bcebos.com/MobileNetV2_pretrained.tar) | 72.15%/90.65% | +| MobieNetV2_0.25x | ImageNet | 0.25x |[MobileNetV2_0.25x](https://paddle-imagenet-models-name.bj.bcebos.com/MobileNetV2_x0_25_pretrained.tar) | 53.21%/76.52% | +| MobieNetV2_0.5x | ImageNet | 0.5x | [MobileNetV2_0.5x](https://paddle-imagenet-models-name.bj.bcebos.com/MobileNetV2_x0_5_pretrained.tar) | 65.03%/85.72% | +| MobieNetV2_1.5x | ImageNet | 1.5x | [MobileNetV2_1.5x](https://paddle-imagenet-models-name.bj.bcebos.com/MobileNetV2_x1_5_pretrained.tar) | 74.12%/91.67% | +| MobieNetV2_2.0x | ImageNet | 2.0x | [MobileNetV2_2.0x](https://paddle-imagenet-models-name.bj.bcebos.com/MobileNetV2_x2_0_pretrained.tar) | 75.23%/92.58% | 用户可以结合实际场景的精度和预测性能要求,选取不同`Depth multiplier`参数的MobileNet模型。 -| 模型 | 数据集合 | 模型加载config设置 | 下载地址 | Accuray Top1/5 Error | -|---|---|---|---|---| -| Xception41 | ImageNet | MODEL.MODEL_NAME: deeplabv3p
MODEL.DEEPLAB.BACKBONE: xception_41
MODEL.DEFAULT_NORM_TYPE: bn| [Xception41_pretrained.tgz](https://paddleseg.bj.bcebos.com/models/Xception41_pretrained.tgz) | 79.5%/94.38% | -| Xception65 | ImageNet | MODEL.MODEL_NAME: deeplabv3p
MODEL.DEEPLAB.BACKBONE: xception_65
MODEL.DEFAULT_NORM_TYPE: bn| [Xception65_pretrained.tgz](https://paddleseg.bj.bcebos.com/models/Xception65_pretrained.tgz) | 80.32%/94.47% | -| Xception71 | ImageNet | MODEL.MODEL_NAME: deeplabv3p
MODEL.DEEPLAB.BACKBONE: xception_71
MODEL.DEFAULT_NORM_TYPE: bn| coming soon | -- | +| 模型 | 数据集合 | 下载地址 | Accuray Top1/5 Error | +|---|---|---|---| +| Xception41 | ImageNet | [Xception41_pretrained.tgz](https://paddleseg.bj.bcebos.com/models/Xception41_pretrained.tgz) | 79.5%/94.38% | +| Xception65 | ImageNet | [Xception65_pretrained.tgz](https://paddleseg.bj.bcebos.com/models/Xception65_pretrained.tgz) | 80.32%/94.47% | +| Xception71 | ImageNet | coming soon | -- | ## COCO预训练模型 -train数据集为coco instance分割数据集合转换成的语义分割数据集合 +数据集为COCO实例分割数据集合转换成的语义分割数据集合 -| 模型 | 数据集合 | 模型加载config设置 | 下载地址 |Output Strid|multi-scale test| mIoU | -|---|---|---|---|---|---|---| -| DeepLabv3+/MobileNetv2/bn | COCO | MODEL.MODEL_NAME: deeplabv3p
MODEL.DEEPLAB.BACKBONE: mobilenet
MODEL.DEEPLAB.DEPTH_MULTIPLIER: 1.0
MODEL.DEFAULT_NORM_TYPE: bn|[deeplabv3plus_coco_bn_init.tgz](https://bj.bcebos.com/v1/paddleseg/deeplabv3plus_coco_bn_init.tgz) | 16 | --| -- | -| DeeplabV3+/Xception65/bn | COCO | MODEL.MODEL_NAME: deeplabv3p
MODEL.DEEPLAB.BACKBONE: xception_65
MODEL.DEFAULT_NORM_TYPE: bn | [xception65_coco.tgz](https://paddleseg.bj.bcebos.com/models/xception65_coco.tgz)| 16 | -- | -- | -| UNet/bn | COCO | MODEL.MODEL_NEME: unet
MODEL.DEFAULT_NORM_TYPE: bn | [unet](https://paddleseg.bj.bcebos.com/models/unet_coco_v3.tgz) | 16 | -- | -- | +| 模型 | 数据集合 | 下载地址 |Output Strid|multi-scale test| mIoU | +|---|---|---|---|---|---| +| DeepLabv3+/MobileNetv2/bn | COCO |[deeplab_mobilenet_x1_0_coco.tgz](https://bj.bcebos.com/v1/paddleseg/deeplab_mobilenet_x1_0_coco.tgz) | 16 | --| -- | +| DeeplabV3+/Xception65/bn | COCO | [xception65_coco.tgz](https://paddleseg.bj.bcebos.com/models/xception65_coco.tgz)| 16 | -- | -- | +| U-Net/bn | COCO | [unet_coco.tgz](https://paddleseg.bj.bcebos.com/models/unet_coco_v3.tgz) | 16 | -- | -- | ## Cityscapes预训练模型 -train数据集合为Cityscapes 训练集合,测试为Cityscapes的验证集合 +train数据集合为Cityscapes训练集合,测试为Cityscapes的验证集合 -| 模型 | 数据集合 | 模型加载config设置 | 下载地址 |Output Stride| mutli-scale test| mIoU on val| -|---|---|---|---|---|---|---| -| DeepLabv3+/MobileNetv2/bn | Cityscapes |MODEL.MODEL_NAME: deeplabv3p
MODEL.DEEPLAB.BACKBONE: mobilenet
MODEL.DEEPLAB.DEPTH_MULTIPLIER: 1.0
MODEL.DEEPLAB.ENCODER_WITH_ASPP: False
MODEL.DEEPLAB.ENABLE_DECODER: False
MODEL.DEFAULT_NORM_TYPE: bn|[mobilenet_cityscapes.tgz](https://paddleseg.bj.bcebos.com/models/mobilenet_cityscapes.tgz) |16|false| 0.698| -| DeepLabv3+/Xception65/gn | Cityscapes |MODEL.MODEL_NAME: deeplabv3p
MODEL.DEEPLAB.BACKBONE: xception_65
MODEL.DEFAULT_NORM_TYPE: gn | [deeplabv3p_xception65_cityscapes.tgz](https://paddleseg.bj.bcebos.com/models/deeplabv3p_xception65_cityscapes.tgz) |16|false| 0.7804 | -| DeepLabv3+/Xception65/bn | Cityscapes | MODEL.MODEL_NAME: deeplabv3p
MODEL.DEEPLAB.BACKBONE: xception_65
MODEL.DEFAULT_NORM_TYPE: bn| [Xception65_deeplab_cityscapes.tgz](https://paddleseg.bj.bcebos.com/models/xception65_bn_cityscapes.tgz) | 16 | false | 0.7715 | -| ICNet/bn | Cityscapes | MODEL.MODEL_NAME: icnet
MODEL.DEFAULT_NORM_TYPE: bn | [icnet_cityscapes.tgz](https://paddleseg.bj.bcebos.com/models/icnet6831.tar.gz) |16|false| 0.6831 | +| 模型 | 数据集合 | 下载地址 |Output Stride| mutli-scale test| mIoU on val| +|---|---|---|---|---|---| +| DeepLabv3+/MobileNetv2/bn | Cityscapes |[mobilenet_cityscapes.tgz](https://paddleseg.bj.bcebos.com/models/mobilenet_cityscapes.tgz) |16|false| 0.698| +| DeepLabv3+/Xception65/gn | Cityscapes |[deeplabv3p_xception65_gn_cityscapes.tgz](https://paddleseg.bj.bcebos.com/models/deeplabv3p_xception65_cityscapes.tgz) |16|false| 0.7824 | +| DeepLabv3+/Xception65/bn | Cityscapes |[deeplabv3p_xception65_bn_cityscapes_.tgz](https://paddleseg.bj.bcebos.com/models/xception65_bn_cityscapes.tgz) | 16 | false | 0.7930 | +| ICNet/bn | Cityscapes |[icnet_cityscapes.tgz](https://paddleseg.bj.bcebos.com/models/icnet6831.tar.gz) |16|false| 0.6831 | +| PSPNet/bn | Cityscapes |[pspnet50_cityscapes.tgz](https://paddleseg.bj.bcebos.com/models/pspnet50_cityscapes.tgz) |16|false| 0.6968 | diff --git a/docs/models.md b/docs/models.md index fb3c043747fa5dc2c3fa25c3b0715328bc7aaeea..680dfe87356db9dd6be181e003598d3eb8967ffe 100644 --- a/docs/models.md +++ b/docs/models.md @@ -1,4 +1,4 @@ -# PaddleSeg 模型列表 +# PaddleSeg 分割模型介绍 ### U-Net U-Net 起源于医疗图像分割,整个网络是标准的encoder-decoder网络,特点是参数少,计算快,应用性强,对于一般场景适应度很高。 diff --git a/docs/usage.md b/docs/usage.md index 6c2e02b963f66e04db0f43e9640a79ef4ecbe515..03418eba8edff90e7350430fa97e83a0d4ec937c 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -1,34 +1,32 @@ -# 训练/评估/预测(可视化) +# 训练/评估/可视化 -PaddleSeg提供了 `训练`/`评估`/`预测(可视化)`/`模型导出` 等四个功能的使用脚本。四个脚本都支持通过不同的Flags来开启特定功能,也支持通过Options来修改默认的[训练配置](./config.md)。四者的使用方式非常接近,如下: +PaddleSeg提供了 **训练**/**评估**/**可视化** 等三个功能的使用脚本。三个脚本都支持通过不同的Flags来开启特定功能,也支持通过Options来修改默认的[训练配置](./config.md)。三者的使用方式非常接近,如下: ```shell # 训练 python pdseg/train.py ${FLAGS} ${OPTIONS} # 评估 python pdseg/eval.py ${FLAGS} ${OPTIONS} -# 预测/可视化 +# 可视化 python pdseg/vis.py ${FLAGS} ${OPTIONS} -# 模型导出 -python pdseg/export_model.py ${FLAGS} ${OPTIONS} ``` -`Note`: +**Note:** -> * FLAGS必须位于OPTIONS之前,否会将会遇到报错,例如如下的例子: -> -> ```shell -> # FLAGS "--cfg configs/cityscapes.yaml" 必须在 OPTIONS "BATCH_SIZE 1" 之前 -> python pdseg/train.py BATCH_SIZE 1 --cfg configs/cityscapes.yaml -> ``` +* FLAGS必须位于OPTIONS之前,否会将会遇到报错,例如如下的例子: -## FLAGS +```shell +# FLAGS "--cfg configs/cityscapes.yaml" 必须在 OPTIONS "BATCH_SIZE 1" 之前 +python pdseg/train.py BATCH_SIZE 1 --cfg configs/cityscapes.yaml +``` + +## 命令行FLAGS列表 |FLAG|支持脚本|用途|默认值|备注| |-|-|-|-|-| |--cfg|ALL|配置文件路径|None|| -|--use_gpu|train/eval/vis|是否使用GPU进行训练|False|| -|--use_mpio|train/eval|是否使用多线程进行IO处理|False|打开该开关会占用一定量的CPU内存,但是可以提高训练速度。
NOTE:windows平台下不支持该功能, 建议使用自定义数据初次训练时不打开,打开会导致数据读取异常不可见。
| +|--use_gpu|ALL|是否使用GPU进行训练|False|| +|--use_mpio|train/eval|是否使用多线程进行IO处理|False|打开该开关会占用一定量的CPU内存,但是可以提高训练速度。
**NOTE:** windows平台下不支持该功能, 建议使用自定义数据初次训练时不打开,打开会导致数据读取异常不可见。
| |--use_tb|train|是否使用TensorBoard记录训练数据|False|| |--log_steps|train|训练日志的打印周期(单位为step)|10|| |--debug|train|是否打印debug信息|False|IOU等指标涉及到混淆矩阵的计算,会降低训练速度| @@ -54,22 +52,21 @@ python pdseg/export_model.py ${FLAGS} ${OPTIONS} ### 下载预训练模型 ```shell -# 下载预训练模型 -wget https://bj.bcebos.com/v1/paddleseg/models/unet_coco_init.tgz -# 解压缩到当前路径下 -tar xvzf unet_coco_init.tgz +# 下载预训练模型并进行解压 +python pretrained_model/download_model.py unet_bn_coco ``` -### 下载Oxford-IIIT数据集 +### 下载Oxford-IIIT Pet数据集 +我们使用了Oxford-IIIT中的猫和狗两个类别数据制作了一个小数据集mini_pet,用于快速体验。 +更多关于数据集的介绍情参考[Oxford-IIIT Pet](https://www.robots.ox.ac.uk/~vgg/data/pets/) + ```shell -# 下载Oxford-IIIT Pet数据集 -wget https://paddleseg.bj.bcebos.com/dataset/mini_pet.zip --no-check-certificate -# 解压缩到当前路径下 -unzip mini_pet.zip +# 下载预训练模型并进行解压 +python dataset/download_pet.py ``` ### 模型训练 -为了方便体验,我们在configs目录下放置了Oxford-IIIT Pet所对应的配置文件`unet_pet.yaml`,可以通过`--cfg`指向该文件来设置训练配置。 +为了方便体验,我们在configs目录下放置了mini_pet所对应的配置文件`unet_pet.yaml`,可以通过`--cfg`指向该文件来设置训练配置。 我们选择GPU 0号卡进行训练,这可以通过环境变量`CUDA_VISIBLE_DEVICES`来指定。 @@ -81,25 +78,23 @@ python pdseg/train.py --use_gpu \ --tb_log_dir train_log \ --cfg configs/unet_pet.yaml \ BATCH_SIZE 4 \ - TRAIN.PRETRAINED_MODEL unet_coco_init \ - DATASET.DATA_DIR mini_pet \ - DATASET.TEST_FILE_LIST mini_pet/file_list/test_list.txt \ - DATASET.TRAIN_FILE_LIST mini_pet/file_list/train_list.txt \ - DATASET.VAL_FILE_LIST mini_pet/file_list/val_list.txt \ - DATASET.VIS_FILE_LIST mini_pet/file_list/val_list.txt \ - TRAIN.SYNC_BATCH_NORM True \ + TRAIN.PRETRAINED_MODEL_DIR pretrained_model/unet_bn_coco \ SOLVER.LR 5e-5 ``` -`NOTE`: -> * 上述示例中,一共存在三套配置方案: PaddleSeg默认配置/unet_pet.yaml/OPTIONS,三者的优先级顺序为 OPTIONS > yaml > 默认配置。这个原则对于train.py/eval.py/vis.py/export_model.py都适用 -> -> * 如果发现因为内存不足而Crash。请适当调低BATCH_SIZE。如果本机GPU内存充足,则可以调高BATCH_SIZE的大小以获得更快的训练速度 +**NOTE:** + +* 上述示例中,一共存在三套配置方案: PaddleSeg默认配置/unet_pet.yaml/OPTIONS,三者的优先级顺序为 OPTIONS > yaml > 默认配置。这个原则对于train.py/eval.py/vis.py都适用 + +* 如果发现因为内存不足而Crash。请适当调低BATCH_SIZE。如果本机GPU内存充足,则可以调高BATCH_SIZE的大小以获得更快的训练速度,BATCH_SIZE增大时,可以适当调高学习率。 + +* 如果在Linux系统下训练,可以使用`--use_mpio`使用多进程I/O,通过提升数据增强的处理速度进而大幅度提升GPU利用率。 + ### 训练过程可视化 -当打开do_eval和use_tb两个开关后,我们可以通过TensorBoard查看训练的效果 +当打开do_eval和use_tb两个开关后,我们可以通过TensorBoard查看边训练边评估的效果。 ```shell tensorboard --logdir train_log --host {$HOST_IP} --port {$PORT} @@ -117,34 +112,21 @@ NOTE: ![](./imgs/tensorboard_image.JPG) ### 模型评估 -训练完成后,我们可以通过eval.py来评估模型效果。由于我们设置的训练EPOCH数量为500,保存间隔为10,因此一共会产生50个定期保存的模型,加上最终保存的final模型,一共有51个模型。我们选择最后保存的模型进行效果的评估: +训练完成后,我们可以通过eval.py来评估模型效果。由于我们设置的训练EPOCH数量为100,保存间隔为10,因此一共会产生10个定期保存的模型,加上最终保存的final模型,一共有11个模型。我们选择最后保存的模型进行效果的评估: + ```shell python pdseg/eval.py --use_gpu \ --cfg configs/unet_pet.yaml \ - DATASET.DATA_DIR mini_pet \ - DATASET.VAL_FILE_LIST mini_pet/file_list/val_list.txt \ TEST.TEST_MODEL test/saved_models/unet_pet/final ``` - -### 模型预测/可视化 +### 模型可视化 通过vis.py来评估模型效果,我们选择最后保存的模型进行效果的评估: ```shell python pdseg/vis.py --use_gpu \ --cfg configs/unet_pet.yaml \ - DATASET.DATA_DIR mini_pet \ - DATASET.TEST_FILE_LIST mini_pet/file_list/test_list.txt \ TEST.TEST_MODEL test/saved_models/unet_pet/final ``` `NOTE` 1. 可视化的图片会默认保存在visual/visual_results目录下,可以通过`--vis_dir`来指定输出目录 2. 训练过程中会使用DATASET.VIS_FILE_LIST中的图片进行可视化显示,而vis.py则会使用DATASET.TEST_FILE_LIST - -### 模型导出 -当确定模型效果满足预期后,我们需要通过export_model.py来导出可用于C++预测库部署的模型: -```shell -python pdseg/export_model.py --cfg configs/unet_pet.yaml \ - TEST.TEST_MODEL test/saved_models/unet_pet/final -``` - -模型会导出到freeze_model目录,接下来就是进行模型的部署,相关步骤请查看[模型部署](../inference/README.md) diff --git a/inference/README.md b/inference/README.md index a29a45b54de496399809081a3dd4bd0c8cbde929..15872fe20bde05e410300bbc7e2ae1586e349a92 100644 --- a/inference/README.md +++ b/inference/README.md @@ -70,7 +70,11 @@ deeplabv3p_xception65_humanseg ### 2. 修改配置 -源代码的`conf`目录下提供了示例人像分割模型的配置文件`humanseg.yaml`, 相关的字段含义和说明如下: + +基于`PaddleSeg`训练的模型导出时,会自动生成对应的预测模型配置文件,请参考文档:[模型导出](../docs/export_model.md)。 + +`inference`源代码(即本目录)的`conf`目录下提供了示例人像分割模型的配置文件`humanseg.yaml`, 相关的字段含义和说明如下: + ```yaml DEPLOY: # 是否使用GPU预测 @@ -102,7 +106,6 @@ DEPLOY: ``` 修改字段`MODEL_PATH`的值为你在**上一步**下载并解压的模型文件所放置的目录即可。 - ### 3. 执行预测 在终端中切换到生成的可执行文件所在目录为当前目录(Windows系统为`cmd`)。 diff --git a/inference/conf/humanseg.yaml b/inference/conf/humanseg.yaml index 537005e18bffe3b62456d873bba12ba01d572291..78195d9e8b4fe2d9ed2758ab76d8e5f88fd104a9 100644 --- a/inference/conf/humanseg.yaml +++ b/inference/conf/humanseg.yaml @@ -5,7 +5,7 @@ DEPLOY: MODEL_FILENAME: "__model__" PARAMS_FILENAME: "__params__" EVAL_CROP_SIZE: (513, 513) - MEAN: [104.008, 116.669, 122.675] + MEAN: [0.5, 0.5, 0.5] STD: [1.0, 1.0, 1.0] IMAGE_TYPE: "rgb" NUM_CLASSES: 2 diff --git a/inference/docs/linux_build.md b/inference/docs/linux_build.md index 80dc2d0f24424ed7e2bdaa0a353cf86bd5b2c9ac..c2200771572c7f57feca5ec6d445529448c29fea 100644 --- a/inference/docs/linux_build.md +++ b/inference/docs/linux_build.md @@ -20,7 +20,9 @@ ### Step2: 下载PaddlePaddle C++ 预测库 fluid_inference -目前仅支持`CUDA 8` 和 `CUDA 9`,请点击 [PaddlePaddle预测库下载地址](https://www.paddlepaddle.org.cn/documentation/docs/zh/develop/advanced_usage/deploy/inference/build_and_install_lib_cn.html)下载对应的版本。 +目前仅支持`CUDA 8` 和 `CUDA 9`,建议使用`cuda9`, 请 [点击下载CUDA9预测库](https://paddle-inference-lib.bj.bcebos.com/latest-gpu-cuda9-cudnn7-avx-mkl/fluid_inference.tgz) + +更多可用版本,请参考:[C++预测库列表](https://www.paddlepaddle.org.cn/documentation/docs/zh/develop/advanced_usage/deploy/inference/build_and_install_lib_cn.html) 下载并解压后`/root/projects/fluid_inference`目录包含内容为: diff --git a/inference/tools/visualize.py b/inference/tools/visualize.py index 87373e9192bf47dab214fdf128b2e290f2124365..93b8410d5eb865a37bfe4259a5bbf645348d469c 100644 --- a/inference/tools/visualize.py +++ b/inference/tools/visualize.py @@ -9,12 +9,11 @@ color_map = [[128, 64, 128], [244, 35, 231], [69, 69, 69], [102, 102, 156], [0, 0, 230], [119, 10, 32]] im = cv2.imread(sys.argv[1]) - -# Please note (224, 224) just for daheng model +shape = im.shape print("visualizing...") -for i in range(0, 224): - for j in range(0, 224): +for i in range(0, shape[0]): + for j in range(0, shape[1]): im[i, j] = color_map[im[i, j, 0]] -cv2.imwrite(sys.argv[1], im) +cv2.imwrite(sys.argv[2], im) print("visualizing done!") diff --git a/pdseg/check.py b/pdseg/check.py index 34372e2511c43a252304f8b22170fc4246ab6696..f1b70a6ae545d93990b860d4eb0f4c9ac1330866 100644 --- a/pdseg/check.py +++ b/pdseg/check.py @@ -266,7 +266,11 @@ def eval_crop_size_check(max_height, max_width, min_aspectratio, max_aspectratio .format(cfg.EVAL_CROP_SIZE[0], cfg.EVAL_CROP_SIZE[1], max_width_rangscaling, cfg.AUG.INF_RESIZE_VALUE)) elif cfg.AUG.AUG_METHOD == "unpadding": - if cfg.EVAL_CROP_SIZE[0] >= cfg.AUG.FIX_RESIZE_SIZE[0] and cfg.EVAL_CROP_SIZE[1] >= cfg.AUG.FIX_RESIZE_SIZE[1]: + if len(cfg.AUG.FIX_RESIZE_SIZE) != 2: + logger.info(error_print("EVAL_CROP_SIZE check")) + logger.info("you set AUG.AUG_METHOD = 'unpadding', but AUG.FIX_RESIZE_SIZE is wrong. " + "AUG.FIX_RESIZE_SIZE should be a tuple of length 2") + elif cfg.EVAL_CROP_SIZE[0] >= cfg.AUG.FIX_RESIZE_SIZE[0] and cfg.EVAL_CROP_SIZE[1] >= cfg.AUG.FIX_RESIZE_SIZE[1]: logger.info(correct_print("EVAL_CROP_SIZE check")) else: logger.info(error_print("EVAL_CROP_SIZE check")) diff --git a/pdseg/data_aug.py b/pdseg/data_aug.py index d845d9c3ac5d40675de35276bbe71bb4f19589a3..474fba9a1236ee8db478a45dd5355f225c875afb 100644 --- a/pdseg/data_aug.py +++ b/pdseg/data_aug.py @@ -374,7 +374,7 @@ def rand_crop(crop_img, crop_seg, mode=ModelPhase.TRAIN): Args: crop_img(numpy.ndarray): 输入图像 crop_seg(numpy.ndarray): 标签图 - mode(string): 模式, 默认训练模式,验证或预测模式时crop尺寸需大于原始图片尺寸, 其他模式无限制 + mode(string): 模式, 默认训练模式,验证或预测、可视化模式时crop尺寸需大于原始图片尺寸 Returns: 裁剪后的图片和标签图 @@ -391,7 +391,7 @@ def rand_crop(crop_img, crop_seg, mode=ModelPhase.TRAIN): crop_width = cfg.EVAL_CROP_SIZE[0] crop_height = cfg.EVAL_CROP_SIZE[1] - if ModelPhase.is_eval(mode) or ModelPhase.is_predict(mode): + if not ModelPhase.is_train(mode): if (crop_height < img_height or crop_width < img_width): raise Exception( "Crop size({},{}) must large than img size({},{}) when in EvalPhase." @@ -410,7 +410,7 @@ def rand_crop(crop_img, crop_seg, mode=ModelPhase.TRAIN): 0, pad_width, cv2.BORDER_CONSTANT, - value=cfg.MEAN) + value=cfg.DATASET.PADDING_VALUE) if crop_seg is not None: crop_seg = cv2.copyMakeBorder( crop_seg, diff --git a/pdseg/eval.py b/pdseg/eval.py index c34a8b5e82aa7dc5a67d5b7386ca833917e334d8..815ebf56f09140a5911bdeb1aa4acd3dbf7950d1 100644 --- a/pdseg/eval.py +++ b/pdseg/eval.py @@ -102,7 +102,7 @@ def evaluate(cfg, ckpt_dir=None, use_gpu=False, use_mpio=False, **kwargs): places = fluid.cuda_places() if use_gpu else fluid.cpu_places() place = places[0] dev_count = len(places) - print("Device count = {}".format(dev_count)) + print("#Device count: {}".format(dev_count)) exe = fluid.Executor(place) exe.run(startup_prog) diff --git a/pdseg/export_model.py b/pdseg/export_model.py index 93c9bea98862572454960c75a6d7548249deebe9..27423bb705ba94d6418e376af04ad06d5d8ccb8e 100644 --- a/pdseg/export_model.py +++ b/pdseg/export_model.py @@ -49,6 +49,32 @@ def parse_args(): sys.exit(1) return parser.parse_args() +def export_inference_config(): + deploy_cfg = '''DEPLOY: + USE_GPU : 1 + MODEL_PATH : "%s" + MODEL_FILENAME : "%s" + PARAMS_FILENAME : "%s" + EVAL_CROP_SIZE : %s + MEAN : %s + STD : %s + IMAGE_TYPE : "%s" + NUM_CLASSES : %d + CHANNELS : %d + PRE_PROCESSOR : "SegPreProcessor" + PREDICTOR_MODE : "ANALYSIS" + BATCH_SIZE : 1 + ''' % (cfg.FREEZE.SAVE_DIR, cfg.FREEZE.MODEL_FILENAME, + cfg.FREEZE.PARAMS_FILENAME, cfg.EVAL_CROP_SIZE, + cfg.MEAN, cfg.STD, cfg.DATASET.IMAGE_TYPE, + cfg.DATASET.NUM_CLASSES, len(cfg.STD)) + if not os.path.exists(cfg.FREEZE.SAVE_DIR): + os.mkdir(cfg.FREEZE.SAVE_DIR) + yaml_path = os.path.join(cfg.FREEZE.SAVE_DIR, 'deploy.yaml') + with open(yaml_path, "w") as fp: + fp.write(deploy_cfg) + return yaml_path + def export_inference_model(args): """ @@ -81,6 +107,9 @@ def export_inference_model(args): model_filename=cfg.FREEZE.MODEL_FILENAME, params_filename=cfg.FREEZE.PARAMS_FILENAME) print("Inference model exported!") + print("Exporting inference model config...") + deploy_cfg_path = export_inference_config() + print("Inference model saved : [%s]" % (deploy_cfg_path)) def main(): diff --git a/pdseg/models/backbone/resnet.py b/pdseg/models/backbone/resnet.py index 5a2b624a9d7a9271d7120f728640142d57533fb4..6eb9f12bc33c97f42664327ada3712c8283943b1 100644 --- a/pdseg/models/backbone/resnet.py +++ b/pdseg/models/backbone/resnet.py @@ -85,7 +85,7 @@ class ResNet(): depth = [3, 8, 36, 3] num_filters = [64, 128, 256, 512] - if self.stem == 'icnet': + if self.stem == 'icnet' or self.stem == 'pspnet': conv = self.conv_bn_layer( input=input, num_filters=int(64 * self.scale), @@ -139,9 +139,9 @@ class ResNet(): else: conv_name = "res" + str(block + 2) + "b" + str(i) else: - conv_name = "conv" + str(block + 2) + '_' + str(1 + i) + conv_name = "res" + str(block + 2) + chr(97 + i) dilation_rate = get_dilated_rate(dilation_dict, block) - + conv = self.bottleneck_block( input=conv, num_filters=int(num_filters[block] * self.scale), @@ -215,6 +215,12 @@ class ResNet(): groups=1, act=None, name=None): + + if self.stem == 'pspnet': + bias_attr=ParamAttr(name=name + "_biases") + else: + bias_attr=False + conv = fluid.layers.conv2d( input=input, num_filters=num_filters, @@ -224,20 +230,21 @@ class ResNet(): dilation=dilation, groups=groups, act=None, - param_attr=ParamAttr(name=name + "/weights"), - bias_attr=False, + param_attr=ParamAttr(name=name + "_weights"), + bias_attr=bias_attr, name=name + '.conv2d.output.1') - bn_name = name + '/BatchNorm/' - return fluid.layers.batch_norm( - input=conv, - act=act, - name=bn_name + '.output.1', - param_attr=ParamAttr(name=bn_name + 'gamma'), - bias_attr=ParamAttr(bn_name + 'beta'), - moving_mean_name=bn_name + 'moving_mean', - moving_variance_name=bn_name + 'moving_variance', - ) + if name == "conv1": + bn_name = "bn_" + name + else: + bn_name = "bn" + name[3:] + return fluid.layers.batch_norm(input=conv, + act=act, + name=bn_name + '.output.1', + param_attr=ParamAttr(name=bn_name + '_scale'), + bias_attr=ParamAttr(bn_name + '_offset'), + moving_mean_name=bn_name + '_mean', + moving_variance_name=bn_name + '_variance', ) def shortcut(self, input, ch_out, stride, is_first, name): ch_in = input.shape[1] @@ -247,12 +254,17 @@ class ResNet(): return input def bottleneck_block(self, input, num_filters, stride, name, dilation=1): + if self.stem == 'pspnet' and self.layers == 101: + strides = [1, stride] + else: + strides = [stride, 1] + conv0 = self.conv_bn_layer( input=input, num_filters=num_filters, filter_size=1, dilation=1, - stride=stride, + stride=strides[0], act='relu', name=name + "_branch2a") if dilation > 1: @@ -262,6 +274,7 @@ class ResNet(): num_filters=num_filters, filter_size=3, dilation=dilation, + stride=strides[1], act='relu', name=name + "_branch2b") conv2 = self.conv_bn_layer( diff --git a/pdseg/models/model_builder.py b/pdseg/models/model_builder.py index 5ff5d51e3f2a8539529d1606a78747f7ecfa61e7..f2ba513a7b14b1b34c2f5dfba2080072cf965356 100644 --- a/pdseg/models/model_builder.py +++ b/pdseg/models/model_builder.py @@ -73,6 +73,7 @@ def map_model_name(model_name): "unet": "unet.unet", "deeplabv3p": "deeplab.deeplabv3p", "icnet": "icnet.icnet", + "pspnet": "pspnet.pspnet", } if model_name in name_dict.keys(): return name_dict[model_name] diff --git a/pdseg/models/modeling/pspnet.py b/pdseg/models/modeling/pspnet.py new file mode 100644 index 0000000000000000000000000000000000000000..8c322b44011f90ac6b29716a51d3e89483bdb3e4 --- /dev/null +++ b/pdseg/models/modeling/pspnet.py @@ -0,0 +1,112 @@ +# coding: utf8 +# copyright (c) 2019 PaddlePaddle Authors. All Rights Reserve. +# +# 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 paddle.fluid as fluid +from paddle.fluid.param_attr import ParamAttr +from models.libs.model_libs import scope, name_scope +from models.libs.model_libs import avg_pool, conv, bn +from models.backbone.resnet import ResNet as resnet_backbone +from utils.config import cfg + +def get_logit_interp(input, num_classes, out_shape, name="logit"): + # 根据类别数决定最后一层卷积输出, 并插值回原始尺寸 + param_attr = fluid.ParamAttr( + name=name + 'weights', + regularizer=fluid.regularizer.L2DecayRegularizer( + regularization_coeff=0.0), + initializer=fluid.initializer.TruncatedNormal(loc=0.0, scale=0.01)) + + with scope(name): + logit = conv(input, + num_classes, + filter_size=1, + param_attr=param_attr, + bias_attr=True, + name=name+'_conv') + logit_interp = fluid.layers.resize_bilinear( + logit, + out_shape=out_shape, + name=name+'_interp') + return logit_interp + + +def psp_module(input, out_features): + # Pyramid Scene Parsing 金字塔池化模块 + # 输入:backbone输出的特征 + # 输出:对输入进行不同尺度pooling, 卷积操作后插值回原始尺寸,并concat + # 最后进行一个卷积及BN操作 + + cat_layers = [] + sizes = (1,2,3,6) + for size in sizes: + psp_name = "psp" + str(size) + with scope(psp_name): + pool = fluid.layers.adaptive_pool2d(input, + pool_size=[size, size], + pool_type='avg', + name=psp_name+'_adapool') + data = conv(pool, out_features, + filter_size=1, + bias_attr=True, + name= psp_name + '_conv') + data_bn = bn(data, act='relu') + interp = fluid.layers.resize_bilinear(data_bn, + out_shape=input.shape[2:], + name=psp_name+'_interp') + cat_layers.append(interp) + cat_layers = [input] + cat_layers[::-1] + cat = fluid.layers.concat(cat_layers, axis=1, name='psp_cat') + + psp_end_name = "psp_end" + with scope(psp_end_name): + data = conv(cat, + out_features, + filter_size=3, + padding=1, + bias_attr=True, + name=psp_end_name) + out = bn(data, act='relu') + + return out + +def resnet(input): + # PSPNET backbone: resnet, 默认resnet50 + # end_points: resnet终止层数 + # dilation_dict: resnet block数及对应的膨胀卷积尺度 + scale = cfg.MODEL.PSPNET.DEPTH_MULTIPLIER + layers = cfg.MODEL.PSPNET.LAYERS + end_points = layers - 1 + dilation_dict = {2:2, 3:4} + model = resnet_backbone(layers, scale, stem='pspnet') + data, _ = model.net(input, + end_points=end_points, + dilation_dict=dilation_dict) + + return data + +def pspnet(input, num_classes): + # Backbone: ResNet + res = resnet(input) + # PSP模块 + psp = psp_module(res, 512) + dropout = fluid.layers.dropout(psp, dropout_prob=0.1, name="dropout") + # 根据类别数决定最后一层卷积输出, 并插值回原始尺寸 + logit = get_logit_interp(dropout, num_classes, input.shape[2:]) + return logit + diff --git a/pdseg/reader.py b/pdseg/reader.py index b4ebb4eba753b91aaa619c012611b7cab0614841..e53b5912e07b1591d4014314f809e6997d925731 100644 --- a/pdseg/reader.py +++ b/pdseg/reader.py @@ -246,7 +246,7 @@ class SegDataset(object): img, grt, rich_crop_max_rotation=cfg.AUG.RICH_CROP.MAX_ROTATION, - mean_value=cfg.MEAN) + mean_value=cfg.DATASET.PADDING_VALUE) img, grt = aug.rand_scale_aspect( img, @@ -261,17 +261,18 @@ class SegDataset(object): SATURATION_JITTER_RATIO, contrast_jitter_ratio=cfg.AUG.RICH_CROP. CONTRAST_JITTER_RATIO) - if cfg.AUG.RICH_CROP.FLIP: - if cfg.AUG.RICH_CROP.FLIP_RATIO <= 0: - n = 0 - elif cfg.AUG.RICH_CROP.FLIP_RATIO >= 1: - n = 1 - else: - n = int(1.0 / cfg.AUG.RICH_CROP.FLIP_RATIO) - if n > 0: - if np.random.randint(0, n) == 0: - img = img[::-1, :, :] - grt = grt[::-1, :] + + if cfg.AUG.FLIP: + if cfg.AUG.FLIP_RATIO <= 0: + n = 0 + elif cfg.AUG.FLIP_RATIO >= 1: + n = 1 + else: + n = int(1.0 / cfg.AUG.FLIP_RATIO) + if n > 0: + if np.random.randint(0, n) == 0: + img = img[::-1, :, :] + grt = grt[::-1, :] if cfg.AUG.MIRROR: if np.random.randint(0, 2) == 1: diff --git a/pdseg/train.py b/pdseg/train.py index 05db0de833d76e43643a46a4b6da328b29f05f82..22a430f7f1bd3ff4c5c1e5ee28a624badc3cac41 100644 --- a/pdseg/train.py +++ b/pdseg/train.py @@ -152,15 +152,15 @@ def load_checkpoint(exe, program): Load checkpoiont from pretrained model directory for resume training """ - print('Resume model training from:', cfg.TRAIN.PRETRAINED_MODEL) - if not os.path.exists(cfg.TRAIN.PRETRAINED_MODEL): + print('Resume model training from:', cfg.TRAIN.RESUME_MODEL_DIR) + if not os.path.exists(cfg.TRAIN.RESUME_MODEL_DIR): raise ValueError("TRAIN.PRETRAIN_MODEL {} not exist!".format( - cfg.TRAIN.PRETRAINED_MODEL)) + cfg.TRAIN.RESUME_MODEL_DIR)) fluid.io.load_persistables( - exe, cfg.TRAIN.PRETRAINED_MODEL, main_program=program) + exe, cfg.TRAIN.RESUME_MODEL_DIR, main_program=program) - model_path = cfg.TRAIN.PRETRAINED_MODEL + model_path = cfg.TRAIN.RESUME_MODEL_DIR # Check is path ended by path spearator if model_path[-1] == os.sep: model_path = model_path[0:-1] @@ -216,7 +216,7 @@ def train(cfg): place = places[0] # Get number of GPU dev_count = len(places) - print("#GPU-Devices: {}".format(dev_count)) + print("#Device count: {}".format(dev_count)) # Make sure BATCH_SIZE can divided by GPU cards assert cfg.BATCH_SIZE % dev_count == 0, ( @@ -255,29 +255,25 @@ def train(cfg): # Resume training begin_epoch = cfg.SOLVER.BEGIN_EPOCH - if cfg.TRAIN.RESUME: + if cfg.TRAIN.RESUME_MODEL_DIR: begin_epoch = load_checkpoint(exe, train_prog) # Load pretrained model - elif os.path.exists(cfg.TRAIN.PRETRAINED_MODEL): - print('Pretrained model dir:', cfg.TRAIN.PRETRAINED_MODEL) + elif os.path.exists(cfg.TRAIN.PRETRAINED_MODEL_DIR): + print('Pretrained model dir:', cfg.TRAIN.PRETRAINED_MODEL_DIR) load_vars = [] + load_fail_vars = [] def var_shape_matched(var, shape): """ Check whehter persitable variable shape is match with current network """ var_exist = os.path.exists( - os.path.join(cfg.TRAIN.PRETRAINED_MODEL, var.name)) + os.path.join(cfg.TRAIN.PRETRAINED_MODEL_DIR, var.name)) if var_exist: var_shape = parse_shape_from_file( - os.path.join(cfg.TRAIN.PRETRAINED_MODEL, var.name)) - if var_shape == shape: - return True - else: - print( - "Variable[{}] shape does not match current network, skip" - " to load it.".format(var.name)) - return False + os.path.join(cfg.TRAIN.PRETRAINED_MODEL_DIR, var.name)) + return var_shape == shape + return False for x in train_prog.list_vars(): if isinstance(x, fluid.framework.Parameter): @@ -285,16 +281,25 @@ def train(cfg): x.name).get_tensor().shape()) if var_shape_matched(x, shape): load_vars.append(x) + else: + load_fail_vars.append(x) if cfg.MODEL.FP16: # If open FP16 training mode, load FP16 var separate - load_fp16_vars(exe, cfg.TRAIN.PRETRAINED_MODEL, train_prog) + load_fp16_vars(exe, cfg.TRAIN.PRETRAINED_MODEL_DIR, train_prog) else: fluid.io.load_vars( - exe, dirname=cfg.TRAIN.PRETRAINED_MODEL, vars=load_vars) - print("Pretrained model loaded successfully!") + exe, dirname=cfg.TRAIN.PRETRAINED_MODEL_DIR, vars=load_vars) + for var in load_vars: + print("Parameter[{}] loaded sucessfully!".format(var.name)) + for var in load_fail_vars: + print("Parameter[{}] don't exist or shape does not match current network, skip" + " to load it.".format(var.name)) + print("{}/{} pretrained parameters loaded successfully!".format( + len(load_vars), + len(load_vars) + len(load_fail_vars))) else: print('Pretrained model dir {} not exists, training from scratch...'. - format(cfg.TRAIN.PRETRAINED_MODEL)) + format(cfg.TRAIN.PRETRAINED_MODEL_DIR)) fetch_list = [avg_loss.name, lr.name] if args.debug: @@ -311,9 +316,6 @@ def train(cfg): exit(1) from tb_paddle import SummaryWriter - - if os.path.exists(args.tb_log_dir): - shutil.rmtree(args.tb_log_dir) log_writer = SummaryWriter(args.tb_log_dir) global_step = 0 diff --git a/pdseg/utils/collect.py b/pdseg/utils/collect.py index 0be64222044f665f430a5adadc90d21298181d62..6b8f2f4eb0b4c98ce3078812f41dacafc3097bc1 100644 --- a/pdseg/utils/collect.py +++ b/pdseg/utils/collect.py @@ -97,6 +97,18 @@ class SegConfig(dict): raise KeyError( 'DATASET.IMAGE_TYPE config error, only support `rgb`, `gray` and `rgba`' ) + if self.MEAN is not None: + self.DATASET.PADDING_VALUE = [x*255.0 for x in self.MEAN] + + if not self.TRAIN_CROP_SIZE: + raise ValueError( + 'TRAIN_CROP_SIZE is empty! Please set a pair of values in format (width, height)' + ) + + if not self.EVAL_CROP_SIZE: + raise ValueError( + 'EVAL_CROP_SIZE is empty! Please set a pair of values in format (width, height)' + ) if reset_dataset: # Ensure file list is use UTF-8 encoding diff --git a/pdseg/utils/config.py b/pdseg/utils/config.py index 0f11284df315d4c0b8a497aaad64b0fbe4bab9f9..12a3e1ba251ff8faa7a4fd7156d84894539c9317 100644 --- a/pdseg/utils/config.py +++ b/pdseg/utils/config.py @@ -65,10 +65,16 @@ cfg.DATASET.DATA_DIM = 3 cfg.DATASET.SEPARATOR = ' ' # 忽略的像素标签值, 默认为255,一般无需改动 cfg.DATASET.IGNORE_INDEX = 255 +# 数据增强是图像的padding值 +cfg.DATASET.PADDING_VALUE = [127.5,127.5,127.5] ########################### 数据增强配置 ###################################### # 图像镜像左右翻转 cfg.AUG.MIRROR = True +# 图像上下翻转开关,True/False +cfg.AUG.FLIP = False +# 图像启动上下翻转的概率,0-1 +cfg.AUG.FLIP_RATIO = 0.5 # 图像resize的固定尺寸(宽,高),非负 cfg.AUG.FIX_RESIZE_SIZE = tuple() # 图像resize的方式有三种: @@ -107,18 +113,14 @@ cfg.AUG.RICH_CROP.CONTRAST_JITTER_RATIO = 0.5 cfg.AUG.RICH_CROP.BLUR = False # 图像启动模糊百分比,0-1 cfg.AUG.RICH_CROP.BLUR_RATIO = 0.1 -# 图像上下翻转开关,True/False -cfg.AUG.RICH_CROP.FLIP = False -# 图像启动上下翻转百分比,0-1 -cfg.AUG.RICH_CROP.FLIP_RATIO = 0.2 ########################### 训练配置 ########################################## # 模型保存路径 cfg.TRAIN.MODEL_SAVE_DIR = '' # 预训练模型路径 -cfg.TRAIN.PRETRAINED_MODEL = '' +cfg.TRAIN.PRETRAINED_MODEL_DIR = '' # 是否resume,继续训练 -cfg.TRAIN.RESUME = False +cfg.TRAIN.RESUME_MODEL_DIR = '' # 是否使用多卡间同步BatchNorm均值和方差 cfg.TRAIN.SYNC_BATCH_NORM = False # 模型参数保存的epoch间隔数,可用来继续训练中断的模型 @@ -196,6 +198,12 @@ cfg.MODEL.ICNET.DEPTH_MULTIPLIER = 0.5 # RESNET 层数 设置 cfg.MODEL.ICNET.LAYERS = 50 +########################## PSPNET模型配置 ###################################### +# RESNET backbone scale 设置 +cfg.MODEL.PSPNET.DEPTH_MULTIPLIER = 1 +# RESNET backbone 层数 设置 +cfg.MODEL.PSPNET.LAYERS = 50 + ########################## 预测部署模型配置 ################################### # 预测保存的模型名称 cfg.FREEZE.MODEL_FILENAME = '__model__' diff --git a/pdseg/vis.py b/pdseg/vis.py index 727edae1f9555badff040e7501253980d10dc3df..e798f2ed5c1b9adb3ad86721761a990ac2ba384f 100644 --- a/pdseg/vis.py +++ b/pdseg/vis.py @@ -198,6 +198,7 @@ def visualize(cfg, interpolation=cv2.INTER_NEAREST) if grt is not None: + grt = grt[0:valid_shape[0], 0:valid_shape[1]] grt = cv2.resize( grt, (org_shape[1], org_shape[0]), interpolation=cv2.INTER_NEAREST) diff --git a/pretrained_model/download_model.py b/pretrained_model/download_model.py index 1cd8b1fca09027b6e179f80675e448f07841ad05..7b44c8038a6c09add5c1a8be292975a21b38fbb0 100644 --- a/pretrained_model/download_model.py +++ b/pretrained_model/download_model.py @@ -22,9 +22,43 @@ sys.path.append(TEST_PATH) from test_utils import download_file_and_uncompress model_urls = { - "deeplabv3plus_mobilenetv2-1-0_bn_cityscapes": + # ImageNet Pretrained + "mobilenetv2-2-0_bn_imagenet": + "https://paddle-imagenet-models-name.bj.bcebos.com/MobileNetV2_x2_0_pretrained.tar", + "mobilenetv2-1-5_bn_imagenet": + "https://paddle-imagenet-models-name.bj.bcebos.com/MobileNetV2_x1_5_pretrained.tar", + "mobilenetv2-1-0_bn_imagenet": + "https://paddle-imagenet-models-name.bj.bcebos.com/MobileNetV2_pretrained.tar", + "mobilenetv2-0-5_bn_imagenet": + "https://paddle-imagenet-models-name.bj.bcebos.com/MobileNetV2_x0_5_pretrained.tar", + "mobilenetv2-0-25_bn_imagenet": + "https://paddle-imagenet-models-name.bj.bcebos.com/MobileNetV2_x0_25_pretrained.tar", + "xception41_imagenet": + "https://paddleseg.bj.bcebos.com/models/Xception41_pretrained.tgz", + "xception65_imagenet": + "https://paddleseg.bj.bcebos.com/models/Xception65_pretrained.tgz", + + # COCO pretrained + "deeplabv3p_mobilenetv2-1-0_bn_coco": + "https://paddleseg.bj.bcebos.com/deeplab_mobilenet_x1_0_coco.tgz", + "deeplabv3p_xception65_bn_coco": + "https://paddleseg.bj.bcebos.com/models/xception65_coco.tgz", + "unet_bn_coco": + "https://paddleseg.bj.bcebos.com/models/unet_coco_v3.tgz", + + # Cityscapes pretrained + "deeplabv3p_mobilenetv2-1-0_bn_cityscapes": "https://paddleseg.bj.bcebos.com/models/mobilenet_cityscapes.tgz", - "unet_bn_coco": "https://paddleseg.bj.bcebos.com/models/unet_coco_v3.tgz" + "deeplabv3p_xception65_gn_cityscapes": + "https://paddleseg.bj.bcebos.com/models/deeplabv3p_xception65_cityscapes.tgz", + "deeplabv3p_xception65_bn_cityscapes": + "https://paddleseg.bj.bcebos.com/models/xception65_bn_cityscapes.tgz", + "unet_bn_coco": + "https://paddleseg.bj.bcebos.com/models/unet_coco_v3.tgz", + "icnet_bn_cityscapes": + "https://paddleseg.bj.bcebos.com/models/icnet_cityscapes.tar.gz", + "pspnet50_bn_cityscapes": + "https://paddleseg.bj.bcebos.com/models/pspnet50_cityscapes.tgz" } if __name__ == "__main__": diff --git a/test/ci/check_code_style.sh b/test/ci/check_code_style.sh index 682b9cd3d19ae7d776a77c5a0b12b36ef8f8a692..f88b8cb8aaaed416e4322aa9e83cbf5eeb0493a3 100644 --- a/test/ci/check_code_style.sh +++ b/test/ci/check_code_style.sh @@ -1,6 +1,6 @@ #!/bin/bash function abort(){ - echo "Your change doesn't follow PaddleHub's code style." 1>&2 + echo "Your change doesn't follow PaddleSeg's code style." 1>&2 echo "Please use pre-commit to check what is wrong." 1>&2 exit 1 } diff --git a/test/configs/deeplabv3p_xception65_cityscapes.yaml b/test/configs/deeplabv3p_xception65_cityscapes.yaml index 612ac31bb304081a6c8900ff08d3ef61df62fbdf..349646f743f10c7970b248b30c258574c8478c68 100644 --- a/test/configs/deeplabv3p_xception65_cityscapes.yaml +++ b/test/configs/deeplabv3p_xception65_cityscapes.yaml @@ -10,18 +10,6 @@ AUG: MIN_SCALE_FACTOR: 0.5 # for stepscaling SCALE_STEP_SIZE: 0.25 # for stepscaling MIRROR: True - RICH_CROP: - ENABLE: False - ASPECT_RATIO: 0.33 - BLUR: True - BLUR_RATIO: 0.1 - FLIP: True - FLIP_RATIO: 0.2 - MAX_ROTATION: 15 - MIN_AREA_RATIO: 0.5 - BRIGHTNESS_JITTER_RATIO: 0.5 - CONTRAST_JITTER_RATIO: 0.5 - SATURATION_JITTER_RATIO: 0.5 BATCH_SIZE: 4 DATASET: DATA_DIR: "./dataset/cityscapes/" @@ -46,8 +34,7 @@ TEST: TEST_MODEL: "snapshots/cityscape_v5/final/" TRAIN: MODEL_SAVE_DIR: "snapshots/cityscape_v5/" - PRETRAINED_MODEL: "pretrain/deeplabv3plus_gn_init" - RESUME: False + PRETRAINED_MODEL_DIR: "pretrain/deeplabv3plus_gn_init" SNAPSHOT_EPOCH: 10 SOLVER: LR: 0.001 diff --git a/test/configs/unet_pet.yaml b/test/configs/unet_pet.yaml index e561e463bbdaddbe532d47a862c3e29095909f95..3a3cf65a09dfbff51e79ca65bd19c1c11fb75d64 100644 --- a/test/configs/unet_pet.yaml +++ b/test/configs/unet_pet.yaml @@ -12,18 +12,6 @@ AUG: MIN_SCALE_FACTOR: 0.75 # for stepscaling SCALE_STEP_SIZE: 0.25 # for stepscaling MIRROR: True - RICH_CROP: - ENABLE: False - ASPECT_RATIO: 0.33 - BLUR: True - BLUR_RATIO: 0.1 - FLIP: True - FLIP_RATIO: 0.2 - MAX_ROTATION: 15 - MIN_AREA_RATIO: 0.5 - BRIGHTNESS_JITTER_RATIO: 0.5 - CONTRAST_JITTER_RATIO: 0.5 - SATURATION_JITTER_RATIO: 0.5 BATCH_SIZE: 6 DATASET: DATA_DIR: "./dataset/pet/" @@ -45,8 +33,7 @@ TEST: TEST_MODEL: "./test/saved_model/unet_pet/final/" TRAIN: MODEL_SAVE_DIR: "./test/saved_models/unet_pet/" - PRETRAINED_MODEL: "./test/models/unet_coco/" - RESUME: False + PRETRAINED_MODEL_DIR: "./test/models/unet_coco/" SNAPSHOT_EPOCH: 10 SOLVER: NUM_EPOCHS: 500 diff --git a/test/local_test_cityscapes.py b/test/local_test_cityscapes.py index 6618695a60aae5f07230c546337b611d7c1cc78a..051faaa1b4e4c769a996b94b411b65815eb3a9e7 100644 --- a/test/local_test_cityscapes.py +++ b/test/local_test_cityscapes.py @@ -45,7 +45,8 @@ if __name__ == "__main__": saved_model = os.path.join(LOCAL_PATH, "saved_model", model_name) parser = argparse.ArgumentParser(description="PaddleSeg loacl test") - parser.add_argument("--devices", + parser.add_argument( + "--devices", dest="devices", help="GPU id of running. if more than one, use spacing to separate.", nargs="+", @@ -75,7 +76,7 @@ if __name__ == "__main__": train( flags=["--cfg", cfg, "--use_gpu", "--log_steps", "10"], options=[ - "SOLVER.NUM_EPOCHS", "1", "TRAIN.PRETRAINED_MODEL", test_model, + "SOLVER.NUM_EPOCHS", "1", "TRAIN.PRETRAINED_MODEL_DIR", test_model, "TRAIN.MODEL_SAVE_DIR", saved_model ], devices=devices) diff --git a/test/local_test_pet.py b/test/local_test_pet.py index 7d0cf58cd1235575fc960769d5142865993b5763..f043d16a5c7a9d7d45db8ce91864a8c5325876b9 100644 --- a/test/local_test_pet.py +++ b/test/local_test_pet.py @@ -46,7 +46,8 @@ if __name__ == "__main__": saved_model = os.path.join(LOCAL_PATH, "saved_model", model_name) parser = argparse.ArgumentParser(description="PaddleSeg loacl test") - parser.add_argument("--devices", + parser.add_argument( + "--devices", dest="devices", help="GPU id of running. if more than one, use spacing to separate.", nargs="+", @@ -59,7 +60,7 @@ if __name__ == "__main__": train( flags=["--cfg", cfg, "--use_gpu", "--log_steps", "10"], options=[ - "SOLVER.NUM_EPOCHS", "1", "TRAIN.PRETRAINED_MODEL", test_model, + "SOLVER.NUM_EPOCHS", "1", "TRAIN.PRETRAINED_MODEL_DIR", test_model, "TRAIN.MODEL_SAVE_DIR", saved_model, "DATASET.TRAIN_FILE_LIST", os.path.join(DATASET_PATH, "mini_pet", "file_list", "train_list.txt"), "DATASET.VAL_FILE_LIST", diff --git a/test/test_utils.py b/test/test_utils.py index 754c7cc14341b3a10dde80fbeffd72faa181b4e9..ed1f8ed89f9ad5204a3534c1c7e2531ce839add0 100644 --- a/test/test_utils.py +++ b/test/test_utils.py @@ -68,7 +68,7 @@ def _download_file(url, savepath, print_progress): if print_progress: done = int(50 * dl / total_length) progress("[%-50s] %.2f%%" % - ('=' * done, float(dl / total_length * 100))) + ('=' * done, float(100 * dl) / total_length)) if print_progress: progress("[%-50s] %.2f%%" % ('=' * 50, 100), end=True) @@ -84,38 +84,42 @@ def _uncompress_file(filepath, extrapath, delete_file, print_progress): else: handler = functools.partial(_uncompress_file_tar, mode="r") - for total_num, index in handler(filepath, extrapath): + for total_num, index, rootpath in handler(filepath, extrapath): if print_progress: done = int(50 * float(index) / total_num) progress( - "[%-50s] %.2f%%" % ('=' * done, float(index / total_num * 100))) + "[%-50s] %.2f%%" % ('=' * done, float(100 * index) / total_num)) if print_progress: progress("[%-50s] %.2f%%" % ('=' * 50, 100), end=True) if delete_file: os.remove(filepath) + return rootpath + def _uncompress_file_zip(filepath, extrapath): files = zipfile.ZipFile(filepath, 'r') filelist = files.namelist() + rootpath = filelist[0] total_num = len(filelist) for index, file in enumerate(filelist): files.extract(file, extrapath) - yield total_num, index + yield total_num, index, rootpath files.close() - yield total_num, index + yield total_num, index, rootpath def _uncompress_file_tar(filepath, extrapath, mode="r:gz"): files = tarfile.open(filepath, mode) filelist = files.getnames() total_num = len(filelist) + rootpath = filelist[0] for index, file in enumerate(filelist): files.extract(file, extrapath) - yield total_num, index + yield total_num, index, rootpath files.close() - yield total_num, index + yield total_num, index, rootpath def download_file_and_uncompress(url, @@ -150,7 +154,9 @@ def download_file_and_uncompress(url, if not os.path.exists(savename): if not os.path.exists(savepath): _download_file(url, savepath, print_progress) - _uncompress_file(savepath, extrapath, delete_file, print_progress) + savename = _uncompress_file(savepath, extrapath, delete_file, + print_progress) + savename = os.path.join(extrapath, savename) shutil.move(savename, extraname) diff --git a/turtorial/finetune_deeplabv3plus.md b/turtorial/finetune_deeplabv3plus.md new file mode 100644 index 0000000000000000000000000000000000000000..abc05f52f73b5d32538fdbd4aecc79c9b5a64da4 --- /dev/null +++ b/turtorial/finetune_deeplabv3plus.md @@ -0,0 +1,129 @@ +# DeepLabv3+模型训练教程 + +* 本教程旨在介绍如何通过使用PaddleSeg提供的 ***`DeeplabV3+/Xception65/BatchNorm`*** 预训练模型在自定义数据集上进行训练。除了该配置之外,DeeplabV3+还支持以下不同[模型组合](#模型组合)的预训练模型,如果需要使用对应模型作为预训练模型,将下述内容中的Xception Backbone中的内容进行替换即可 + +* 在阅读本教程前,请确保您已经了解过PaddleSeg的[快速入门](../README.md#快速入门)和[基础功能](../README.md#基础功能)等章节,以便对PaddleSeg有一定的了解 + +* 本教程的所有命令都基于PaddleSeg主目录进行执行 + +## 一. 准备待训练数据 + +我们提前准备好了一份数据集,通过以下代码进行下载 + +```shell +python dataset/download_pet.py +``` + +## 二. 下载预训练模型 + +关于PaddleSeg支持的所有预训练模型的列表,我们可以从[模型组合](#模型组合)中查看我们所需模型的名字和配置 + +接着下载对应的预训练模型 + +```shell +python pretrained_model/download_model.py deeplabv3p_xception65_bn_cityscapes +``` + +## 三. 准备配置 + +接着我们需要确定相关配置,从本教程的角度,配置分为三部分: + +* 数据集 + * 训练集主目录 + * 训练集文件列表 + * 测试集文件列表 + * 评估集文件列表 +* 预训练模型 + * 预训练模型名称 + * 预训练模型的backbone网络 + * 预训练模型的Normalization类型 + * 预训练模型路径 +* 其他 + * 学习率 + * Batch大小 + * ... + +在三者中,预训练模型的配置尤为重要,如果模型或者BACKBONE配置错误,会导致预训练的参数没有加载,进而影响收敛速度。预训练模型相关的配置如第二步所展示。 + +数据集的配置和数据路径有关,在本教程中,数据存放在`dataset/mini_pet`中 + +其他配置则根据数据集和机器环境的情况进行调节,最终我们保存一个如下内容的yaml配置文件,存放路径为`configs/test_deeplabv3p_pet.yaml` + +```yaml +# 数据集配置 +DATASET: + DATA_DIR: "./dataset/mini_pet/" + NUM_CLASSES: 3 + TEST_FILE_LIST: "./dataset/mini_pet/file_list/test_list.txt" + TRAIN_FILE_LIST: "./dataset/mini_pet/file_list/train_list.txt" + VAL_FILE_LIST: "./dataset/mini_pet/file_list/val_list.txt" + VIS_FILE_LIST: "./dataset/mini_pet/file_list/test_list.txt" + +# 预训练模型配置 +MODEL: + MODEL_NAME: "deeplabv3p" + DEFAULT_NORM_TYPE: "bn" + DEEPLAB: + BACKBONE: "xception_65" + +# 其他配置 +TRAIN_CROP_SIZE: (512, 512) +EVAL_CROP_SIZE: (512, 512) +AUG: + AUG_METHOD: "unpadding" + FIX_RESIZE_SIZE: (512, 512) +BATCH_SIZE: 4 +TRAIN: + PRETRAINED_MODEL_DIR: "./pretrained_model/deeplabv3p_xception65_bn_coco/" + MODEL_SAVE_DIR: "./saved_model/deeplabv3p_xception65_bn_pet/" + SNAPSHOT_EPOCH: 10 +TEST: + TEST_MODEL: "./saved_model/deeplabv3p_xception65_bn_pet/final" +SOLVER: + NUM_EPOCHS: 100 + LR: 0.005 + LR_POLICY: "poly" + OPTIMIZER: "sgd" +``` + +## 四. 配置/数据校验 + +在开始训练和评估之前,我们还需要对配置和数据进行一次校验,确保数据和配置是正确的。使用下述命令启动校验流程 + +```shell +python pdseg/check.py --cfg ./configs/test_deeplabv3p_pet.yaml +``` + + +## 五. 开始训练 + +校验通过后,使用下述命令启动训练 + +```shell +python pdseg/train.py --use_gpu --cfg ./configs/test_deeplabv3p_pet.yaml +``` + +## 六. 进行评估 + +模型训练完成,使用下述命令启动评估 + +```shell +python pdseg/eval.py --use_gpu --cfg ./configs/test_deeplabv3p_pet.yaml +``` + +## 模型组合 + +|预训练模型名称|BackBone|Norm Type|数据集|配置| +|-|-|-|-|-| +|mobilenetv2-2-0_bn_imagenet|-|bn|ImageNet|MODEL.MODEL_NAME: deeplabv3p
MODEL.DEEPLAB.BACKBONE: mobilenet
MODEL.DEEPLAB.DEPTH_MULTIPLIER: 2.0
MODEL.DEFAULT_NORM_TYPE: bn| +|mobilenetv2-1-5_bn_imagenet|-|bn|ImageNet|MODEL.MODEL_NAME: deeplabv3p
MODEL.DEEPLAB.BACKBONE: mobilenet
MODEL.DEEPLAB.DEPTH_MULTIPLIER: 1.5
MODEL.DEFAULT_NORM_TYPE: bn| +|mobilenetv2-1-0_bn_imagenet|-|bn|ImageNet|MODEL.MODEL_NAME: deeplabv3p
MODEL.DEEPLAB.BACKBONE: mobilenet
MODEL.DEEPLAB.DEPTH_MULTIPLIER: 1.0
MODEL.DEFAULT_NORM_TYPE: bn| +|mobilenetv2-0-5_bn_imagenet|-|bn|ImageNet|MODEL.MODEL_NAME: deeplabv3p
MODEL.DEEPLAB.BACKBONE: mobilenet
MODEL.DEEPLAB.DEPTH_MULTIPLIER: 0.5
MODEL.DEFAULT_NORM_TYPE: bn| +|mobilenetv2-0-25_bn_imagenet|-|bn|ImageNet|MODEL.MODEL_NAME: deeplabv3p
MODEL.DEEPLAB.BACKBONE: mobilenet
MODEL.DEEPLAB.DEPTH_MULTIPLIER: 0.25
MODEL.DEFAULT_NORM_TYPE: bn| +|xception41_imagenet|-|bn|ImageNet|MODEL.MODEL_NAME: deeplabv3p
MODEL.DEEPLAB.BACKBONE: xception_41
MODEL.DEFAULT_NORM_TYPE: bn| +|xception65_imagenet|-|bn|ImageNet|MODEL.MODEL_NAME: deeplabv3p
MODEL.DEEPLAB.BACKBONE: xception_65
MODEL.DEFAULT_NORM_TYPE: bn| +|deeplabv3p_mobilenetv2-1-0_bn_coco|MobileNet V2|bn|COCO|MODEL.MODEL_NAME: deeplabv3p
MODEL.DEEPLAB.BACKBONE: mobilenet
MODEL.DEEPLAB.DEPTH_MULTIPLIER: 1.0
MODEL.DEEPLAB.ENCODER_WITH_ASPP: False
MODEL.DEEPLAB.ENABLE_DECODER: False
MODEL.DEFAULT_NORM_TYPE: bn| +|deeplabv3p_xception65_bn_coco|Xception|bn|COCO|MODEL.MODEL_NAME: deeplabv3p
MODEL.DEEPLAB.BACKBONE: xception_65
MODEL.DEFAULT_NORM_TYPE: bn | +|deeplabv3p_mobilenetv2-1-0_bn_cityscapes|MobileNet V2|bn|Cityscapes|MODEL.MODEL_NAME: deeplabv3p
MODEL.DEEPLAB.BACKBONE: mobilenet
MODEL.DEEPLAB.DEPTH_MULTIPLIER: 1.0
MODEL.DEEPLAB.ENCODER_WITH_ASPP: False
MODEL.DEEPLAB.ENABLE_DECODER: False
MODEL.DEFAULT_NORM_TYPE: bn| +|deeplabv3p_xception65_gn_cityscapes|Xception|gn|Cityscapes|MODEL.MODEL_NAME: deeplabv3p
MODEL.DEEPLAB.BACKBONE: xception_65
MODEL.DEFAULT_NORM_TYPE: gn| +|**deeplabv3p_xception65_bn_cityscapes**|Xception|bn|Cityscapes|MODEL.MODEL_NAME: deeplabv3p
MODEL.DEEPLAB.BACKBONE: xception_65
MODEL.DEFAULT_NORM_TYPE: bn| diff --git a/turtorial/finetune_icnet.md b/turtorial/finetune_icnet.md new file mode 100644 index 0000000000000000000000000000000000000000..54aa9d43c395abe32b76cfcdf74759fe58753cd7 --- /dev/null +++ b/turtorial/finetune_icnet.md @@ -0,0 +1,120 @@ +# ICNet模型训练教程 + +* 本教程旨在介绍如何通过使用PaddleSeg提供的 ***`ICNet`*** 预训练模型在自定义数据集上进行训练 + +* 在阅读本教程前,请确保您已经了解过PaddleSeg的[快速入门](../README.md#快速入门)和[基础功能](../README.md#基础功能)等章节,以便对PaddleSeg有一定的了解 + +* 本教程的所有命令都基于PaddleSeg主目录进行执行 + +## 一. 准备待训练数据 + +我们提前准备好了一份数据集,通过以下代码进行下载 + +```shell +python dataset/download_pet.py +``` + +## 二. 下载预训练模型 + +关于PaddleSeg支持的所有预训练模型的列表,我们可以从[模型组合](#模型组合)中查看我们所需模型的名字和配置。 + +接着下载对应的预训练模型 + +```shell +python pretrained_model/download_model.py icnet_bn_cityscapes +``` + +## 三. 准备配置 + +接着我们需要确定相关配置,从本教程的角度,配置分为三部分: + +* 数据集 + * 训练集主目录 + * 训练集文件列表 + * 测试集文件列表 + * 评估集文件列表 +* 预训练模型 + * 预训练模型名称 + * 预训练模型的backbone网络 + * 预训练模型的Normalization类型 + * 预训练模型路径 +* 优化策略 + * 学习率 + * Batch Size + * ... + +在三者中,预训练模型的配置尤为重要,如果模型或者BACKBONE配置错误,会导致预训练的参数没有加载,进而影响收敛速度。预训练模型相关的配置如第二步所示。 + +数据集的配置和数据路径有关,在本教程中,数据存放在`dataset/mini_pet`中 + +其他配置则根据数据集和机器环境的情况进行调节,最终我们保存一个如下内容的yaml配置文件,存放路径为`configs/test_pet.yaml` + +```yaml +# 数据集配置 +DATASET: + DATA_DIR: "./dataset/mini_pet/" + NUM_CLASSES: 3 + TEST_FILE_LIST: "./dataset/mini_pet/file_list/test_list.txt" + TRAIN_FILE_LIST: "./dataset/mini_pet/file_list/train_list.txt" + VAL_FILE_LIST: "./dataset/mini_pet/file_list/val_list.txt" + VIS_FILE_LIST: "./dataset/mini_pet/file_list/test_list.txt" + + +# 预训练模型配置 +MODEL: + MODEL_NAME: "icnet" + DEFAULT_NORM_TYPE: "bn" + MULTI_LOSS_WEIGHT: "[1.0, 0.4, 0.16]" + ICNET: + DEPTH_MULTIPLIER: 0.5 + +# 其他配置 +TRAIN_CROP_SIZE: (512, 512) +EVAL_CROP_SIZE: (512, 512) +AUG: + AUG_METHOD: "unpadding" + FIX_RESIZE_SIZE: (512, 512) +BATCH_SIZE: 4 +TRAIN: + PRETRAINED_MODEL_DIR: "./pretrained_model/icnet_bn_cityscapes/" + MODEL_SAVE_DIR: "./saved_model/icnet_pet/" + SNAPSHOT_EPOCH: 10 +TEST: + TEST_MODEL: "./saved_model/icnet_pet/final" +SOLVER: + NUM_EPOCHS: 100 + LR: 0.005 + LR_POLICY: "poly" + OPTIMIZER: "sgd" +``` + +## 四. 配置/数据校验 + +在开始训练和评估之前,我们还需要对配置和数据进行一次校验,确保数据和配置是正确的。使用下述命令启动校验流程 + +```shell +python pdseg/check.py --cfg ./configs/test_pet.yaml +``` + + +## 五. 开始训练 + +校验通过后,使用下述命令启动训练 + +```shell +python pdseg/train.py --use_gpu --cfg ./configs/test_pet.yaml +``` + +## 六. 进行评估 + +模型训练完成,使用下述命令启动评估 + +```shell +python pdseg/eval.py --use_gpu --cfg ./configs/test_pet.yaml +``` + +## 模型组合 + +|预训练模型名称|BackBone|Norm|数据集|配置| +|-|-|-|-|-| +|icnet_bn_cityscapes|-|bn|Cityscapes|MODEL.MODEL_NAME: icnet
MODEL.DEFAULT_NORM_TYPE: bn
MULTI_LOSS_WEIGHT: [1.0, 0.4, 0.16]| diff --git a/turtorial/finetune_pspnet.md b/turtorial/finetune_pspnet.md new file mode 100644 index 0000000000000000000000000000000000000000..931c3c5f7515e2ebec3d4fccf3069ecc6d6c00fb --- /dev/null +++ b/turtorial/finetune_pspnet.md @@ -0,0 +1,121 @@ +# PSPNET模型训练教程 + +* 本教程旨在介绍如何通过使用PaddleSeg提供的 ***`PSPNET`*** 预训练模型在自定义数据集上进行训练 + +* 在阅读本教程前,请确保您已经了解过PaddleSeg的[快速入门](../README.md#快速入门)和[基础功能](../README.md#基础功能)等章节,以便对PaddleSeg有一定的了解 + +* 本教程的所有命令都基于PaddleSeg主目录进行执行 + +## 一. 准备待训练数据 + +我们提前准备好了一份数据集,通过以下代码进行下载 + +```shell +python dataset/download_pet.py +``` + +## 二. 下载预训练模型 + +关于PaddleSeg支持的所有预训练模型的列表,我们可以从[模型组合](#模型组合)中查看我们所需模型的名字和配置。 + +接着下载对应的预训练模型 + +```shell +python pretrained_model/download_model.py pspnet50_bn_cityscapes +``` + +## 三. 准备配置 + +接着我们需要确定相关配置,从本教程的角度,配置分为三部分: + +* 数据集 + * 训练集主目录 + * 训练集文件列表 + * 测试集文件列表 + * 评估集文件列表 +* 预训练模型 + * 预训练模型名称 + * 预训练模型的backbone网络 + * 预训练模型的Normalization类型 + * 预训练模型路径 +* 优化策略 + * 学习率 + * Batch Size + * ... + +在三者中,预训练模型的配置尤为重要,如果模型或者BACKBONE配置错误,会导致预训练的参数没有加载,进而影响收敛速度。预训练模型相关的配置如第二步所示。 + +数据集的配置和数据路径有关,在本教程中,数据存放在`dataset/mini_pet`中 + +其他配置则根据数据集和机器环境的情况进行调节,最终我们保存一个如下内容的yaml配置文件,存放路径为`configs/test_pet.yaml` + +```yaml +# 数据集配置 +DATASET: + DATA_DIR: "./dataset/mini_pet/" + NUM_CLASSES: 3 + TEST_FILE_LIST: "./dataset/mini_pet/file_list/test_list.txt" + TRAIN_FILE_LIST: "./dataset/mini_pet/file_list/train_list.txt" + VAL_FILE_LIST: "./dataset/mini_pet/file_list/val_list.txt" + VIS_FILE_LIST: "./dataset/mini_pet/file_list/test_list.txt" + + +# 预训练模型配置 +MODEL: + MODEL_NAME: "pspnet" + DEFAULT_NORM_TYPE: "bn" + PSPNET: + DEPTH_MULTIPLIER: 1 + LAYERS: 50 + +# 其他配置 +TRAIN_CROP_SIZE: (512, 512) +EVAL_CROP_SIZE: (512, 512) +AUG: + AUG_METHOD: "unpadding" + FIX_RESIZE_SIZE: (512, 512) +BATCH_SIZE: 4 +TRAIN: + PRETRAINED_MODEL_DIR: "./pretrained_model/pspnet50_bn_cityscapes/" + MODEL_SAVE_DIR: "./saved_model/pspnet_pet/" + SNAPSHOT_EPOCH: 10 +TEST: + TEST_MODEL: "./saved_model/pspnet_pet/final" +SOLVER: + NUM_EPOCHS: 100 + LR: 0.005 + LR_POLICY: "poly" + OPTIMIZER: "sgd" +``` + +## 四. 配置/数据校验 + +在开始训练和评估之前,我们还需要对配置和数据进行一次校验,确保数据和配置是正确的。使用下述命令启动校验流程 + +```shell +python pdseg/check.py --cfg ./configs/test_pet.yaml +``` + + +## 五. 开始训练 + +校验通过后,使用下述命令启动训练 + +```shell +python pdseg/train.py --use_gpu --cfg ./configs/test_pet.yaml +``` + +## 六. 进行评估 + +模型训练完成,使用下述命令启动评估 + +```shell +python pdseg/eval.py --use_gpu --cfg ./configs/test_pet.yaml +``` + +## 模型组合 + +|预训练模型名称|BackBone|Norm|数据集|配置| +|-|-|-|-|-| +|pspnet50_bn_cityscapes|ResNet50|bn|Cityscapes|MODEL.MODEL_NAME: pspnet
MODEL.DEFAULT_NORM_TYPE: bn
MODEL.PSPNET.LAYERS: 50| +|pspnet101_bn_cityscapes|ResNet101|bn|Cityscapes|MODEL.MODEL_NAME: pspnet
MODEL.DEFAULT_NORM_TYPE: bn
MODEL.PSPNET.LAYERS: 101| diff --git a/turtorial/finetune_unet.md b/turtorial/finetune_unet.md new file mode 100644 index 0000000000000000000000000000000000000000..656541d842c3e89ca0f41f50e23bb9a2b120988b --- /dev/null +++ b/turtorial/finetune_unet.md @@ -0,0 +1,117 @@ +# U-Net模型训练教程 + +* 本教程旨在介绍如何通过使用PaddleSeg提供的 ***`U-Net`*** 预训练模型在自定义数据集上进行训练 + +* 在阅读本教程前,请确保您已经了解过PaddleSeg的[快速入门](../README.md#快速入门)和[基础功能](../README.md#基础功能)等章节,以便对PaddleSeg有一定的了解 + +* 本教程的所有命令都基于PaddleSeg主目录进行执行 + +## 一. 准备待训练数据 + +我们提前准备好了一份数据集,通过以下代码进行下载 + +```shell +python dataset/download_pet.py +``` + +## 二. 下载预训练模型 + +关于PaddleSeg支持的所有预训练模型的列表,我们可以从[模型组合](#模型组合)中查看我们所需模型的名字和配置。 + +接着下载对应的预训练模型 + +```shell +python pretrained_model/download_model.py unet_bn_coco +``` + +## 三. 准备配置 + +接着我们需要确定相关配置,从本教程的角度,配置分为三部分: + +* 数据集 + * 训练集主目录 + * 训练集文件列表 + * 测试集文件列表 + * 评估集文件列表 +* 预训练模型 + * 预训练模型名称 + * 预训练模型的backbone网络 + * 预训练模型的Normalization类型 + * 预训练模型路径 +* 其他 + * 学习率 + * Batch大小 + * ... + +在三者中,预训练模型的配置尤为重要,如果模型或者BACKBONE配置错误,会导致预训练的参数没有加载,进而影响收敛速度。预训练模型相关的配置如第二步所展示。 + +数据集的配置和数据路径有关,在本教程中,数据存放在`dataset/mini_pet`中 + +其他配置则根据数据集和机器环境的情况进行调节,最终我们保存一个如下内容的yaml配置文件,存放路径为`configs/test_unet_pet.yaml` + +```yaml +# 数据集配置 +DATASET: + DATA_DIR: "./dataset/mini_pet/" + NUM_CLASSES: 3 + TEST_FILE_LIST: "./dataset/mini_pet/file_list/test_list.txt" + TRAIN_FILE_LIST: "./dataset/mini_pet/file_list/train_list.txt" + VAL_FILE_LIST: "./dataset/mini_pet/file_list/val_list.txt" + VIS_FILE_LIST: "./dataset/mini_pet/file_list/test_list.txt" + + +# 预训练模型配置 +MODEL: + MODEL_NAME: "unet" + DEFAULT_NORM_TYPE: "bn" + +# 其他配置 +TRAIN_CROP_SIZE: (512, 512) +EVAL_CROP_SIZE: (512, 512) +AUG: + AUG_METHOD: "unpadding" + FIX_RESIZE_SIZE: (512, 512) +BATCH_SIZE: 4 +TRAIN: + PRETRAINED_MODEL_DIR: "./pretrained_model/unet_bn_coco/" + MODEL_SAVE_DIR: "./saved_model/unet_pet/" + SNAPSHOT_EPOCH: 10 +TEST: + TEST_MODEL: "./saved_model/unet_pet/final" +SOLVER: + NUM_EPOCHS: 100 + LR: 0.005 + LR_POLICY: "poly" + OPTIMIZER: "adam" +``` + +## 四. 配置/数据校验 + +在开始训练和评估之前,我们还需要对配置和数据进行一次校验,确保数据和配置是正确的。使用下述命令启动校验流程 + +```shell +python pdseg/check.py --cfg ./configs/test_unet_pet.yaml +``` + + +## 五. 开始训练 + +校验通过后,使用下述命令启动训练 + +```shell +python pdseg/train.py --use_gpu --cfg ./configs/test_unet_pet.yaml +``` + +## 六. 进行评估 + +模型训练完成,使用下述命令启动评估 + +```shell +python pdseg/eval.py --use_gpu --cfg ./configs/test_unet_pet.yaml +``` + +## 模型组合 + +|预训练模型名称|BackBone|Norm|数据集|配置| +|-|-|-|-|-| +|unet_bn_coco|-|bn|Cityscapes|MODEL.MODEL_NAME: unet
MODEL.DEFAULT_NORM_TYPE: bn|