Paddle
Модель для инференса PaddlePaddle — это граф model.pdmodel рядом с файлом весов model.pdiparams. LibreYOLO экспортирует статический ONNX-граф с opset 15, конвертирует его через X2Paddle и упаковывает результат вместе с metadata.yaml, поэтому он загружается через ту же фабрику, что и любая другая среда выполнения.
- Флаг
export(format="paddle")- Записывает
- Директорию с model.pdmodel, model.pdiparams и metadata.yaml
- Дополнительно
pip install "libreyolo[paddle]"- Загружается обратно
LibreYOLO("weights/LibreYOLO9t_paddle", device="cpu")- Бэкенд
libreyolo.backends.paddle.PaddleBackend- Формы
- Статические, батч 1, opset 15. Все три требования жёстко проверяются.
- Точность
- Только FP32, только CPU.
- Стек инструментов
- PaddlePaddle 2.6.2, X2Paddle 1.6.0, ONNX 1.17 или ниже, проверяется в точности
Установка
# Python 3.10–3.12. Проверенный путь для Windows — WSL2 с Ubuntu 22.04.pip install "libreyolo[paddle]"python -c "from importlib.metadata import version; print(version('paddlepaddle'), version('x2paddle'), version('onnx'))"Дополнительная зависимость закрепляет ровно тот стек, на котором измерялся
паритет: PaddlePaddle 2.6.2, X2Paddle 1.6.0 и ONNX 1.17 или ниже. Эти
закрепления проверяются при экспорте, а не только при установке, и другая версия
вызывает ImportError с указанием ожидаемой. Новые релизы Paddle отвергают часть
статического кода, который генерирует X2Paddle 1.6.0, поэтому упасть сразу лучше,
чем выдать артефакт, который никто не проверял.
Экспорт
from libreyolo import LibreYOLO model = LibreYOLO("LibreYOLO9t.pt") # Записывает директорию weights/LibreYOLO9t_paddlepath = model.export(format="paddle")print(path)libreyolo export --model LibreYOLO9t.pt --format paddlemodel.export( format="paddle", imgsz=640, # int; квадратный холст этого семейства batch=1, # любое другое значение вызывает ValueError dynamic=False, # True вызывает ValueError simplify=True, # False вызывает ValueError opset=15, # любое другое значение вызывает ValueError output_path=None, # None записывает weights/<stem>_paddle)Четыре аргумента зафиксированы, а не просто имеют значения по умолчанию.
dynamic должен быть False, batch — 1, simplify — True, чтобы граф
конвертации был полностью статическим, а opset — 15: это потолок, который
принимает X2Paddle 1.6.0. Любое другое значение вызывает ошибку ещё до
трассировки.
На промежуточном графе выполняется одна нормализация. ONNX считает пропущенный dilation у MaxPool равным единице, PyTorch записывает явный атрибут из одних единиц, а X2Paddle 1.6.0 его отвергает, поэтому экспортёр убирает это избыточное значение по умолчанию и оставляет заданную операцию без изменений.
Артефакт — это директория: model.pdmodel, model.pdiparams и
metadata.yaml. Python-код, который X2Paddle генерирует во время конвертации, в
неё не входит.
Запуск артефакта
from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("weights/LibreYOLO9t_paddle", device="cpu")result = model.predict(SAMPLE_IMAGE)print(result.boxes.xyxy[:3])libreyolo predict --model weights/LibreYOLO9t_paddle \ --source https://raw.githubusercontent.com/LibreYOLO/libreyolo/release/libreyolo/assets/parkour.jpg --device cpu --savefrom libreyolo.backends.paddle import PaddleBackend # То, что LibreYOLO() создаёт для директории Paddle. Тот же объект# Results, без маршрутизации через фабрику.backend = PaddleBackend("weights/LibreYOLO9t_paddle", device="cpu")result = backend.predict("parkour.jpg")print(result.boxes.xyxy[:3])import numpy as npimport paddle.inference as paddle_inferimport yaml directory = "weights/LibreYOLO9t_paddle"config = paddle_infer.Config( f"{directory}/model.pdmodel", f"{directory}/model.pdiparams")config.disable_gpu()config.disable_mkldnn()config.switch_ir_optim(False) predictor = paddle_infer.create_predictor(config)handle = predictor.get_input_handle(predictor.get_input_names()[0])handle.reshape([1, 3, 640, 640])handle.copy_from_cpu(np.zeros((1, 3, 640, 640), dtype=np.float32))predictor.run()for name in predictor.get_output_names(): print(name, predictor.get_output_handle(name).copy_to_cpu().shape) meta = yaml.safe_load(open(f"{directory}/metadata.yaml"))print(meta["model_family"], meta["task"], meta["names"]) # Предобработка и постобработка на этом пути — на вас.LibreYOLO() распознаёт любую директорию, где лежат и model.pdmodel, и
model.pdiparams, читает metadata.yaml и возвращает тот же объект Results,
что и чекпойнт. Устройство, отличное от auto или cpu, вызывает ошибку: этот
бэкенд работает только на CPU.
Фабрика создаёт PaddleBackend — он экспортируется из libreyolo и импортируется
как libreyolo.backends.paddle.PaddleBackend. Создавайте его сами, когда нужен
бэкенд без маршрутизации по суффиксам, которую делает фабрика, — например, чтобы
явно передать task= для директории, чей metadata.yaml писали не вы. Его
predict() принимает те же источники и возвращает те же результаты.
Сниппет с чистой средой выполнения повторяет то, что настраивает бэкенд, а три отключённые опции выключены намеренно. Пайплайн CPU-фьюзинга в Paddle 2.6 может падать при оптимизации больших графов gather и scatter, которые порождает deformable attention, поэтому паритет измерялся на переносимом статическом графе без фьюзинга. Предобработка, декодирование, NMS и пересчёт координат на этом пути ложатся на вас.
Ограничения
Ни динамических форм, ни FP16, ни INT8, ни встроенного NMS, ни GPU-среды выполнения.
Проверенные комбинации: детекция YOLO9, детекция YOLO9-E2E и YOLO9-P2, детекция, оценка позы и сегментация EC, детекция RT-DETRv4, D-FINE, DEIM и DEIMv2, а также детекция и оценка позы YOLO-NAS. Для каждой проверены конвертация, повторная загрузка в CPU-среде выполнения, паритет сырых выходов и совпадение с опубликованными результатами.
Заблокированы, с причиной, записанной для каждой комбинации:
| Комбинация | Причина |
|---|---|
| RF-DETR, все задачи | Нужны ONNX opset 17 и GridSample; X2Paddle 1.6.0 принимает opset 15 или ниже и не имеет маппера для GridSample |
| Детекция RT-DETR и RT-DETRv2 | Обученным графам нужен GridSample на opset 16 или новее |
| Сегментация D-FINE | Конвертируется и загружается обратно, но относительная RMS-ошибка логитов маски — 3.52%, а минимальный IoU по сопоставленным маскам — 0.582 |
| Сегментация YOLO9 | В LibreYOLO YOLO9 — только детекция |
| Сегментация RTMDet-Ins | У декодирования маски с динамическим ядром нет контракта для экспортированных сред выполнения |
Всё, что не указано как проверенное или заблокированное, отклоняется с примечанием, что комбинация не проверялась на пути конвертации из ONNX в Paddle.
Полная таблица семейств и задач — матрица экспорта. Для одной комбинации:
libreyolo formats --family yolo9 --task detect