Обучение PP-PicoDet для детектирования объектов
Что это за модель
PicoDet - это модель для слабых вычислительных систем, которая заявляется, как более качественная и быстрая альтернатива YoloX и другим моделям. Вот ссылка:
https://gitee.com/paddlepaddle/PaddleDetection/blob/release/2.3/configs/picodet/README.md
Собственно вот ее результаты:
Ну и сравнение с известными моделями:
Т.е., если сравнить YoloX-Nano и PicoDet-S по mAP0.5-0.96, то это 25.8 против 30.7 для разрешения 416x416. Существенный прирост.
Посмотрим далее, как обучить эту модель, поскольку обучение не такое простое, как к примеру в YoloX (про YOLOX пример обучения напишу в другой раз).
Настройка среды
Я для упрощения решил использовать docker. Сначала проверяем версию CUDA на машине, она должна быть больше или равной требуемой.
Затем запускаем docker Paddle в фоне (он сначала загрузится):
sudo docker run -d --runtime=nvidia -it --entrypoint "" -v "/home/ubuntu:/paddle" -p 8888:8888 paddlepaddle/paddle:2.6.0-gpu-cuda11.2-cudnn8.2-trt8.0 /bin/bash
После чего заходим в докер:
docker exec -it 90b73013182c /bin/bash
и устанавливаем Юпитер:
pip install notebook
Далее запускаем юпитер в фоне:
jupyter notebook --ip 0.0.0.0 --allow-root --port 8888 &
Он покажет нужный токен, по которому вы можете зайти на сервер в браузере, а консоль можно закрыть
Создаем новый ноутбук и в нем заходим в основную директорию:
%cd /paddle
Проверяем, работает ли среда paddle:
!python -c "import paddle; print(paddle.__version__)"
У меня выдало 2.6.0
PaddleDetection
В докере нет модуля PaddleDetection, его нужно устанавливать самостоятельно. Сначала клонируем репозиторий:
!git clone https://github.com/PaddlePaddle/PaddleDetection.git
Затем устанавливаем
%cd PaddleDetection
!pip install -r requirements.txt
Уже на этом этапе у меня часть модулей не установилась. Но я пошел дальше.
!python setup.py install
Здесь тоже было несколько красных строк ошибок. Как следствие - часть модулей не установилось и я поставил вручную.
!pip install -U lazy_loader
!pip install pyparsing
!pip install cycler
!pip install kiwisolver
!pip install matplotlib
!pip install joblib
!pip install threadpoolctl
!pip install pytz
Проверяем работоспособность:
!python ppdet/modeling/tests/test_architectures.py
Warning: Unable to use numba in PP-Tracking, please install numba, for example(python3.7): `pip install numba==0.56.4`Warning: Unable to use numba in PP-Tracking, please install numba, for example(python3.7): `pip install numba==0.56.4`W0208 10:47:51.617843 1193 gpu_resources.cc:119] Please NOTE: device: 0, GPU Compute Capability: 8.6, Driver API Version: 12.0, Runtime API Version: 11.2W0208 10:47:51.637682 1193 gpu_resources.cc:164] device: 0, cuDNN Version: 8.1........----------------------------------------------------------------------
Ran 7 tests in 6.534s
OK
Наконец тест удачен
Подготовка выборки и настройка обучающих файлов
У меня была некоторая база из 1 класса и изображений 320x320 в формате YOLO. Сначала надо сконвертировать в COCO. Создаем каталоги:
!mkdir ./dataset/
!mkdir ./dataset/images
!mkdir ./dataset/images/train2017
!mkdir ./dataset/images/val2017
!mkdir ./dataset/images/annotations
Копируем туда изображения:
!cp ./mydataset/train/*.jpg ./dataset/images/train2017
!cp ./mydataset/valid/*.jpg ./dataset/images/val2017
Устанавливаем утилиту для конвертации:
!pip install globox
И конвертируем:
from globox import *
from pathlib import Path
def convert(path,names_file,save_file):
annotations = AnnotationSet.from_yolo_v5(
folder=path,
image_folder=path)
annotations.save_coco(save_file,auto_ids=True)
convert('./mydataset/train/','classes.names','./dataset/images/annotations/train.json')
convert('./mydataset/valid/','classes.names','./dataset/images/annotations/valid.json')
Далее в папке ./configs/datasets/ я создал файл my_detection.yml, описывающий мой датасет:
metric: COCO
num_classes: 1
TrainDataset:
name: COCODataSet
image_dir: train2017
anno_path: annotations/train.json
dataset_dir: dataset/images
data_fields: ['image', 'gt_bbox', 'gt_class', 'is_crowd']
EvalDataset:
name: COCODataSet
image_dir: val2017
anno_path: annotations/valid.json
dataset_dir: dataset/images
allow_empty: true
TestDataset:
name: ImageFolder
anno_path: annotations/valid.json # also support txt (like VOC's label_list.txt)
dataset_dir: dataset/images # if set, anno_path will be 'dataset_dir/anno_path'
После чего использовал picodet_s_320_coco_lcnet.yml для создания собственного настроечного файла обучения:
config = """
_BASE_: [
'../datasets/my_detection.yml',
'../runtime.yml',
'_base_/picodet_v2.yml',
'_base_/optimizer_300e.yml',
'_base_/picodet_320_reader.yml',
]
pretrain_weights: https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/legendary_models/PPLCNet_x0_75_pretrained.pdparams
weights: output/picodet_s_320_coco/best_model
find_unused_parameters: True
use_ema: true
epoch: 200
snapshot_epoch: 5
LCNet:
scale: 0.75
feature_maps: [3, 4, 5]
LCPAN:
out_channels: 96
PicoHeadV2:
conv_feat:
name: PicoFeat
feat_in: 96
feat_out: 96
num_convs: 2
num_fpn_stride: 4
norm_type: bn
share_cls_reg: True
use_se: True
feat_in_chan: 96
TrainReader:
batch_size: 64
LearningRate:
base_lr: 0.32
schedulers:
- !CosineDecay
max_epochs: 300
- !LinearWarmup
start_factor: 0.1
steps: 200
"""
with open("./configs/picodet/picodet_s_320_coco_lcnet_my.yml", 'w') as f:
f.write(config)
Наконец можно перейти к обучению.
Тренировка и экспорт модели
Запуск обучения:
!python tools/train.py -c configs/picodet/picodet_s_320_coco_lcnet_my.yml --eval
Конечный результат обучения и ключевые показатели:
Далее нужно получить саму модель. Это делается так:
!python tools/export_model.py -c configs/picodet/picodet_s_320_coco_lcnet_my.yml \
-o weights=output/best_model.pdparams --output_dir=inference_model
Однако тут меня встретила ошибка
RuntimeError: Can't call main_program when full_graph=False. Use paddle.jit.to_static(full_graph=True) instead.
Благодаря ссылке https://github.com/PaddlePaddle/PaddleDetection/commit/3e8b1076f5483b5eae4fce79738ce5f14f27a412
исправил trainer.py, добавив full_graph = True (Как может быть такое в релизном проекте?????)
После чего модель была получена.
Далее получаем ONNX.
Устанавливаем нужные компоненты:
!pip install onnx
!pip install paddle2onnx
!pip install onnx-simplifier
Экспортируем модель:
!paddle2onnx --model_dir inference_model/picodet_s_320_coco_lcnet_my/ \
--model_filename model.pdmodel \
--params_filename model.pdiparams \
--opset_version 11 \
--save_file picodet_s_320_coco.onnx
Упрощаем ее:
!python -m onnxsim picodet_s_320_coco.onnx picodet_s_320_coco_processed.onnx
Что выдает такой результат:
Ну и можно посмотреть саму модель в Netron:
С использованием в TensorRT есть проблемы из-за внешних динамических слоев:
[6] Invalid Node - p2o.TopK.0
This version of TensorRT only supports input K as an initializer. Try applying constant folding on the model using Polygraphy: https://github.com/NVIDIA/TensorRT/tree/master/tools/Polygraphy/examples/cli/surgeon/02_folding_constants
Но это уже другая история