paddledetection的最新develop版本支持旋转框预测
2022.11.15:发布基于PP-YOLOE+扩展的旋转框、小目标检测SOTA模型
项目地址:https://gitee.com/paddlepaddle/PaddleDetection/tree/develop/configs/rotate#%E7%AE%80%E4%BB%8B
旋转框检测模型PP-YOLOE-R
Anchor-free旋转框检测SOTA模型,精度速度双高
云边一体,s/m/l/x四个模型适配不用算力硬件
部署友好,避免使用特殊算子,能够轻松使用TensorRT加速
支持选择框训练与部署的目前是paddledetection的最新develop版本,因此请注意自己的paddledetection版本,develop版下载地址为:
https://gitee.com/paddlepaddle/PaddleDetection/tree/develop
如果编译失败可以纠正一下GCC和paddle版本,然后删除上次失败残余的文件,重新执行命令
博主操作成功的GCC版本为 GCC8.0,paddle版本为2.4(补充说明,linux系统支持安装多个gcc版本,只需将系统默认的gcc、g++重新链接到新安装的gcc、g++即可,不用卸载以前安装的旧版本)
cd ~/HPG/PaddleDetection/ppdet/ext_op/
python setup.py install
如果更新paddle版本,在import paddle报错的话,请使用以下命令添加LD_LIBRARY_PATH,注意其中的路径要修改为自己python环境中的paddle/lib路径
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/home/{username}/anaconda3/envs/paddle/lib
这里通过export 命令设置零时环境变量,用于后续数据格式转换
export train_dir='/home/{username}/MyDota/train/'
export val_dir='/home/{username}/MyDota/val/'
对应数据的路径存储如下所示,这是标准的dota,已经划分好了数据集。
DOTA数据集是一个大规模的遥感图像数据集,包含旋转框和水平框的标注。可以从DOTA数据集官网下载数据集并解压,解压后的数据集目录结构如下所示:
${DOTA_ROOT}
├── test
│ └── images
├── train
│ ├── images
│ └── labelTxt
└── val
├── images
└── labelTxt
对于有标注的数据,每一张图片会对应一个同名的txt文件,文件中每一行为一个旋转框的标注,其格式如下:
x1 y1 x2 y2 x3 y3 x4 y4 class_name difficult
示例数据:
532 604 534 592 565 608 567 595 ship 0
384 251 393 231 443 275 452 256 ship 0
原始的prepare_data.py文件是针对原始dota数据集的,在转换数据时需要设置图像切片参数,而博主的数据集已经完成切片操作了,故此对prepare_data.py文件进行修改。主要就是添加了一个命令行参数only_change_format,用于控制脚本只转换数据格式,不进行切片。
打开configs/rotate/tools/prepare_data.py,使用以下内容进行替换
同时,需要按照自己的数据情况修改 class_names,博主的dota数据中只有ship和car两个类别,故此 class_names = [‘ship’,‘car’]
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import os
import argparse
from convert import load_dota_infos, data_to_coco
from slicebase import SliceBase
wordname_15 = [
'plane', 'baseball-diamond', 'bridge', 'ground-track-field',
'small-vehicle', 'large-vehicle', 'ship', 'tennis-court',
'basketball-court', 'storage-tank', 'soccer-ball-field', 'roundabout',
'harbor', 'swimming-pool', 'helicopter'
]
wordname_16 = wordname_15 + ['container-crane']
wordname_18 = wordname_16 + ['airport', 'helipad']
DATA_CLASSES = {
'dota10': wordname_15,
'dota15': wordname_16,
'dota20': wordname_18
}
def parse_args():
parser = argparse.ArgumentParser('prepare data for training')
parser.add_argument(
'--input_dirs',
nargs='+',
type=str,
default=None,
help='input dirs which contain image and labelTxt dir')
parser.add_argument(
'--output_dir',
type=str,
default=None,
help='output dirs which contain image and labelTxt dir and coco style json file'
)
parser.add_argument(
'--coco_json_file',
type=str,
default='',
help='coco json annotation files')
parser.add_argument('--subsize', type=int, default=1024, help='patch size')
parser.add_argument('--gap', type=int, default=200, help='step size')
parser.add_argument(
'--data_type', type=str, default='dota10', help='data type')
parser.add_argument(
'--rates',
nargs='+',
type=float,
default=[1.],
help='scales for multi-sclace training')
parser.add_argument(
'--nproc', type=int, default=8, help='the processor number')
parser.add_argument(
'--iof_thr',
type=float,
default=0.5,
help='the minimal iof between a object and a window')
parser.add_argument(
'--only_change_format',
action='store_true',
default=False,
help='only processing image')
parser.add_argument(
'--image_only',
action='store_true',
default=False,
help='only processing image')
args = parser.parse_args()
return args
def load_dataset(input_dir, nproc, data_type):
if 'dota' in data_type.lower():
infos = load_dota_infos(input_dir, nproc)
else:
raise ValueError('only dota dataset is supported now')
return infos
def main():
args = parse_args()
infos = []
for input_dir in args.input_dirs:
infos += load_dataset(input_dir, args.nproc, args.data_type)
if args.only_change_format==False:
slicer = SliceBase(
args.gap,
args.subsize,
args.iof_thr,
num_process=args.nproc,
image_only=args.image_only)
slicer.slice_data(infos, args.rates, args.output_dir)
else:
args.output_dir=args.input_dirs[0]
print("only_change_format,input_dirs should contain image and labelTxt folder:")
print(args.output_dir)
if args.coco_json_file:
infos = load_dota_infos(args.output_dir, args.nproc)
coco_json_file = os.path.join(args.output_dir, args.coco_json_file)
class_names = ['ship','car']#DATA_CLASSES[args.data_type]
data_to_coco(infos, coco_json_file, class_names, args.nproc)
if __name__ == '__main__':
main()
通过以下命令可以将原始的dota数据转换为coco格式,
python configs/rotate/tools/prepare_data.py --input_dirs ${train_dir} --only_change_format --coco_json_file DOTA_train.json
python configs/rotate/tools/prepare_data.py --input_dirs ${val_dir} --only_change_format --coco_json_file DOTA_val.json
paddledetection官网关于旋转框使用标准COCO数据格式,你可以将你的数据集转换成COCO格式以训练模型。COCO标准数据格式的标注信息中包含以下信息:
‘annotations’: [
{
‘id’: 2083, ‘category_id’: 9, ‘image_id’: 9008,
‘bbox’: [x, y, w, h], # 水平框标注
‘segmentation’: [[x1, y1, x2, y2, x3, y3, x4, y4]], # 旋转框标注
…
}
…
]
需要注意的是bbox的标注是水平框标注,segmentation为旋转框四个点的标注(顺时针或逆时针均可)。在旋转框训练时bbox是可以缺省,一般推荐根据旋转框标注segmentation生成。 在PaddleDetection 2.4及之前的版本,bbox为旋转框标注[x, y, w, h, angle],segmentation缺省,目前该格式已不再支持,请下载最新数据集或者转换成标准COCO格式。在进行选择框训练时,仅会从segmentation字段中加载boxes信息
mv命令用于移动文件,通过该命令将生成好的json文件存入到dota的目录下
ln命令用于创建软连接,通过软连接(快捷方式)的形式可以避免图像复制,节省存储空间
mv ${train_dir}/DOTA_train.json dataset/dota/
mv ${val_dir}/DOTA_val.json dataset/dota/
ln -s ${val_dir}/images dataset/dota/val_images -r
ln -s ${train_dir}/images dataset/dota/train_images -r
文件具体路径为:configs/datasets/dota.yml
这里也要注意num_classes的设置,按照实际情况设置。
metric: RBOX
num_classes: 2
TrainDataset:
!COCODataSet
image_dir: train_images
anno_path: DOTA_train.json
dataset_dir: dataset/dota/
data_fields: ['image', 'gt_bbox', 'gt_class', 'is_crowd', 'gt_poly']
EvalDataset:
!COCODataSet
image_dir: val_images
anno_path: DOTA_val.json
dataset_dir: dataset/dota/
data_fields: ['image', 'gt_bbox', 'gt_class', 'is_crowd', 'gt_poly']
TestDataset:
!ImageFolder
anno_path: test1024/DOTA_test1024.json
dataset_dir: dataset/dota/
在paddledetection中训练旋转框和正框的命令都是一样的,可以参考paddle 31 安装paddledetection并训练自己的数据集(支持voc与coco数据集)
python -m paddle.distributed.launch --gpus 1 tools/train.py \
-c configs/rotate/ppyoloe_r/ppyoloe_r_crn_s_3x_dota.yml --eval \
-o pretrian_weights=output/ppyoloe_r_crn_s_3x_dota/best_model \
--use_vdl=true
--vdl_log_dir=vdl_dir/scalar
此外,paddledetection也支持旋转框模型的导出与部署,且与正常模型的导出部署流程是一样的,后续将会补充实现onnx部署教程。