简体中文 | English
模型规范主要分为:新增文件的开发规范,可拓展模块的开发规范,导出和测试预测模型,新增模型的PR checklist。
每个新增文件都需要进行自查和修正,主要包含copyright
部分,import
部分和编码规范checklist
。
copyright
部分创建空文件pspnet.py
后,在文件顶部添加以下copyright
。
PaddleSeg
中每个新增的文件都需要添加相应的版权信息,注意其中年份按照当前自然年改写。
# Copyright (c) 2022 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
部分该部分为导入模型所需要的package,所有Python文件需要按照以下顺序导入三个类型的package
:
Python
源生自带package
;package
,即pip
或conda install
的package
;PaddleSeg
中的package
。以下举例,注:不同类型package
空行,删掉未使用的package
,长度相差太大按照递增顺序排列。
import os
import numpy as np
import paddle.nn as nn
import paddle.nn.functional as F
from paddleseg.cvlibs import manager
from paddleseg.models import layers
from paddleseg.utils import utils
checklist
这部分主要面向 python 说明编码中需要注意的规范,其中大部分编码规范会有pre-commit进行校验修正,更多可以参考谷歌编程规范。
目前PaddleSeg
支持model, loss, backbone, transform, dataset
的组件拓展,所有新增的组件都需要按照下面规范进行自查和修正。
backbone和模型的规范相近,transform的规范较为简单,因此下面主要对模型,损失和数据集进行规范说明。
模型实现部分以PSPNet的开发为例进行说明。
开发PSPNet
,需要在paddleseg/models
目录下创建pspnet.py
,文件名的字母均为小写。整个文件内容分为三个部分,copyright
部分, import
部分, 模型实现部分,前两部分参考前面新增文件的开发规范
的说明。
模型实现的结构按顺序分为三个部分,主模型,分割头,辅助模块。若模型没有backbone则只有主模型和辅助模块,这里以三部分为例。
模型声明规范
该部分在import部分之后,为模型实现的第一部分,即要求将主模型放在文件顶部。
@manager.MODELS.add_component
class PSPNet(nn.Layer):
主模型的class,需要继承 nn.Layer;
添加英文注释
The xxx implementation based on PaddlePaddle.
";The original article refers to
" + 作者名和文章名 + 论文链接;optional
,然后在该参数注释末尾添加"Default: xx
";Returns,Raises
说明函数/方法返回值和可能会有的报错。@manager.MODELS.add_component
class PSPNet(nn.Layer):
"""
The PSPNet implementation based on PaddlePaddle.
The original article refers to
Zhao, Hengshuang, et al. "Pyramid scene parsing network"
(https://openaccess.thecvf.com/content_cvpr_2017/papers/Zhao_Pyramid_Scene_Parsing_CVPR_2017_paper.pdf).
Args:
num_classes (int): The unique number of target classes.
backbone (Paddle.nn.Layer): Backbone network, currently support Resnet50/101.
backbone_indices (tuple, optional): Two values in the tuple indicate the indices of output of backbone.
pp_out_channels (int, optional): The output channels after Pyramid Pooling Module. Default: 1024.
bin_sizes (tuple, optional): The out size of pooled feature maps. Default: (1,2,3,6).
enable_auxiliary_loss (bool, optional): A bool value indicates whether adding auxiliary loss. Default: True.
align_corners (bool, optional): An argument of F.interpolate. It should be set to False when the feature size is even,
e.g. 1024x512, otherwise it is True, e.g. 769x769. Default: False.
pretrained (str, optional): The path or url of pretrained model. Default: None.
"""
__init__规范
__init__
中,参数列表的建议顺序为:num_classes, backbone, backbone_indices, ......, align_corners, in_channels, pretrained
。参数的具体含义可以参考前面PSPNet示例的注释。前面参数若出现,则按照上面的顺序,其他中间参数顺序可以自由调整;*args, **kwargs
;super().__init__()
保持空参数;self.init_weight()
,加载pretrained
指定的模型参数;in_channels
用来指定输入图片的通道数。如果主模型没有使用backbone,则需要在主模型的__init__
中设置in_channels
(默认值为3)。如果主模型使用了backbone,则不需要在主模型的__init__
中设置in_channels
,而是需要在backbone的__init__
中设置in_channels
(默认值为3)。def __init__(self,
num_classes,
backbone,
backbone_indices=(2, 3),
pp_out_channels=1024,
bin_sizes=(1, 2, 3, 6),
enable_auxiliary_loss=True,
align_corners=False,
pretrained=None):
super().__init__()
...
self.init_weight()
forward 规范
resize
到原图大小,按列表形式返回,第一个元素为主输出,其他为辅助输出。paddle.shape(x)
,不要使用x.shape
,否则在导出预测模型的时候可能出现动转静失败的问题。def forward(self, x):
feat_list = self.backbone(x)
logit_list = self.head(feat_list)
return [
F.interpolate(
logit,
paddle.shape(x)[2:],
mode='bilinear',
align_corners=self.align_corners) for logit in logit_list
]
init_weight规范
utils.load_entire_model
函数即可。paddleseg.cvlib
中的 param_init
实现。# 带有 backbone 的对整个模型进行加载
def init_weight(self):
if self.pretrained is not None:
utils.load_entire_model(self, self.pretrained)
# 不带 backbone 的自身模型初始化
def init_weight(self):
"""Initialize the parameters of model parts."""
for sublayer in self.sublayers():
if isinstance(sublayer, nn.Conv2D):
param_init.normal_init(sublayer.weight, std=0.001)
elif isinstance(sublayer, (nn.BatchNorm, nn.SyncBatchNorm)):
param_init.constant_init(sublayer.weight, value=1.0)
param_init.constant_init(sublayer.bias, value=0.0)
骨干网络Backbone的实现和主模型大体类似,具体可以参考paddleseg/models/backbones/mobilenetv2.py
的实现。
骨干网络要求__init__
函数输入参数必须有in_channels
,表示输入图片的通道数,默认等于3。
骨干网络通常有多个输出特征图,比如返回分别是4、8、16和32倍下采样的特征图,便于在主模型中使用backbone_indices
来选择使用backbone的特定特征图。
骨干网络类必须有self.feat_channels
属性,表示所有输出特征图的通道数。
骨干网络通常有不同尺寸型号,分别通过函数进行定义,使用@manager.BACKBONES.add_component
注册,示例如下。
@manager.BACKBONES.add_component
def MobileNetV2_x0_25(**kwargs):
model = MobileNetV2(scale=0.25, **kwargs)
return model
@manager.BACKBONES.add_component
def MobileNetV2_x0_5(**kwargs):
model = MobileNetV2(scale=0.5, **kwargs)
return model
目前PaddleSeg
里面的模型只有单分割头模型,所以分割头模块直接以主模型名+Head来命名。注释规范与主模型保持一致。
class PSPNetHead(nn.Layer):
如果是轻量级分割模型,没有backbone
,可以看做是只有分割头的模型,那么为了简洁可以不用写Head,而把逻辑直接写在主模型部分中。
除了主模型,和分割头之外的代码段都称为辅助模块。目前PaddleSeg
已经提供了常见的辅助模块,例如SyncBN, ConvBNReLU, FCN (AuxLayer), PPModule, ASPP, AttentionBlock
等等,详细查看paddleseg/models/layers
。
PaddleSeg
内置辅助模块;开发完模型后,在paddleseg/models/__init__.py
中添加导入信息。若没有其他loss
的添加,就完成了一个模型的开发。
from .pspnet import *
损失开发的规范以paddleseg/models/losses/cross_entropy_loss.py
为例:
损失声明规范:
manager
装饰器;nn.Layer
;ignore_index
等ignore_index
来设置忽略的label数值。@manager.LOSSES.add_component
class CrossEntropyLoss(nn.Layer):
"""
Implements the cross entropy loss function.
Args:
weight (tuple|list|ndarray|Tensor, optional): A manual rescaling weight
given to each class. Its length must be equal to the number of classes.
Default ``None``.
ignore_index (int64, optional): Specifies a target value that is ignored
and does not contribute to the input gradient. Default ``255``.
top_k_percent_pixels (float, optional): the value lies in [0.0, 1.0]. When its value < 1.0, only compute the loss for
the top k percent pixels (e.g., the top 20% pixels). This is useful for hard pixel mining. Default ``1.0``.
data_format (str, optional): The tensor format to use, 'NCHW' or 'NHWC'. Default ``'NCHW'``.
"""
不推荐大家直接在paddleseg/dataset/
目录下新增数据集Class,来实现支持新的数据集。建议大家参考准备自定义数据集文档,将数据集整理成PaddleSeg推荐的格式,基于txt文件来配置DataSet
。
数据集开发的规范以paddleseg/dataset/cityscapes.py
为例,文件中仅声明一个和数据集名字一致的类。
建立新的数据集文件,则在paddleseg/dataset
中创建对应数据集名字的文件。
在类头部添加装饰器;
@manager.DATASETS.add_component
类方法继承Dataset
类;
文档部分描述数据集来源,数据集结构,还有参数含义等。
from paddleseg.dataset import Dataset
@manager.DATASETS.add_component
class Cityscapes(Dataset):
"""
Cityscapes dataset `https://www.cityscapes-dataset.com/`.
The folder structure is as follow:
cityscapes
|
|--leftImg8bit
| |--train
| |--val
| |--test
|
|--gtFine
| |--train
| |--val
| |--test
Make sure there are **labelTrainIds.png in gtFine directory. If not, please run the conver_cityscapes.py in tools.
Args:
transforms (list): Transforms for image.
dataset_root (str): Cityscapes dataset directory.
mode (str, optional): Which part of dataset to use. it is one of ('train', 'val', 'test'). Default: 'train'.
edge (bool, optional): Whether to compute edge while training. Default: False
"""
__init__
中参数全部显式写出,不能包括变长参数比如:*args, **kwargs
;super().__init__()
保持空参数;__init__
方法中建立 self.file_list
,之后就根据其中元素的路径读取对应图片。开发模型,我们不仅要关注模型精度的正确性,还需要检查模型导出和预测部署的正确性。只有模型可以顺利部署,才算真正开发完成一个模型。
开发模型是使用PaddlePaddle的动态图模式,我们需要将动态图的模型导出为静态图的预测模型,实现更快的部署推理速度。
将动态图的模型导出为静态图的预测模型,使用的是动转静技术,此处不展开介绍,具体说明请参考文档。
请参考文档导出静态图预测模型。如果没有报错,静态图的预测模型会保存到指定目录。如果报错,根据log修改组网代码,再次导出。
请参考文档,在X86 CPU或者NV GPU上使用Paddle Inference Python API加载导出的预测模型,读取单/多张图片进行测试,查看分割结果图片是否正确。
参考代码提交规范,完成代码提交前的准备,包含拉取最新内容、切换分支等。
在configs
目录下有以模型名命名的子目录,比如pspnet
,其中包含模型yml配置文件和README.md
,详细参考示例。
模型yml配置文件的文件命名方式为模型名+backbone+out_stride+数据集+训练分辨率+训练单卡iters.yml
,不含部分就略去,详细参考配置项文档。
README.md
中模型原文文献的reference风格采用Chicago,即全部作者名,详细参考示例。
README.md
中,提供至少一个数据集上的训练和测试结果,格式如下表格
Resolution
表示训练数据集预处理时crop的图像尺寸。mIoU、mIoU(flip)、mIoU(ms+flip)
是模型在验证集上的评估精度。flip
表示测试使用水平翻转;ms
表示multi-scale
,即使用三种scale
[0.75, 1.0, 1.25]进行测试;ms+flip
表示使用这两种数据处理方式进行测试。模型评估的详细使用方法,请参考模型评估。Model | Backbone | Resolution | Training Iters | mIoU | mIoU (flip) | mIoU (ms+flip) | Links |
---|---|---|---|---|---|---|---|
model | log | vdl |
新增的代码文件,参考本文档前面介绍的新增文件的开发规范
和可拓展模块的开发规范
进行自查和改正,参考导出和测试预测模型
完成测试并在PR中反馈给Reviewer。
Dear OpenI User
Thank you for your continuous support to the Openl Qizhi Community AI Collaboration Platform. In order to protect your usage rights and ensure network security, we updated the Openl Qizhi Community AI Collaboration Platform Usage Agreement in January 2024. The updated agreement specifies that users are prohibited from using intranet penetration tools. After you click "Agree and continue", you can continue to use our services. Thank you for your cooperation and understanding.
For more agreement content, please refer to the《Openl Qizhi Community AI Collaboration Platform Usage Agreement》