Paddle

Los modelos de inferencia de PaddlePaddle son un grafo model.pdmodel junto a un archivo de pesos model.pdiparams. LibreYOLO exporta un grafo ONNX estático con opset 15, lo convierte con X2Paddle y empaqueta el resultado con un metadata.yaml para que se cargue a través de la misma factoría que cualquier otro runtime.

Flag
export(format="paddle")
Escribe
Un directorio con model.pdmodel, model.pdiparams y metadata.yaml
Extra
pip install "libreyolo[paddle]"
Se recarga con
LibreYOLO("weights/LibreYOLO9t_paddle", device="cpu")
Backend
libreyolo.backends.paddle.PaddleBackend
Formas
Estáticas, batch 1, opset 15. Las tres se imponen.
Precisión
Solo FP32, solo CPU.
Toolchain
PaddlePaddle 2.6.2, X2Paddle 1.6.0, ONNX 1.17 o anterior, comprobados de forma exacta

Instalación

Instalación
# Python 3.10 a 3.12. WSL2 con Ubuntu 22.04 es la ruta validada en Windows.pip install "libreyolo[paddle]"
Confirmar las versiones fijadas
python -c "from importlib.metadata import version; print(version('paddlepaddle'), version('x2paddle'), version('onnx'))"

El extra fija exactamente el stack que midió el trabajo de paridad: PaddlePaddle 2.6.2, X2Paddle 1.6.0 y ONNX 1.17 o anterior. Esas versiones fijadas se comprueban en el momento de exportar, no solo al instalar, y una versión distinta lanza un ImportError que nombra la esperada. Las versiones más nuevas de Paddle rechazan partes del código estático que genera X2Paddle 1.6.0, así que fallar pronto es mejor que producir un artefacto que nadie ha validado.

Exportación

Python
from libreyolo import LibreYOLO model = LibreYOLO("LibreYOLO9t.pt") # Escribe el directorio weights/LibreYOLO9t_paddlepath = model.export(format="paddle")print(path)
CLI
libreyolo export --model LibreYOLO9t.pt --format paddle
Argumentos
model.export(    format="paddle",    imgsz=640,        # int; el lienzo cuadrado de esta familia    batch=1,          # cualquier otro valor lanza ValueError    dynamic=False,    # True lanza ValueError    simplify=True,    # False lanza ValueError    opset=15,         # cualquier otro valor lanza ValueError    output_path=None, # None escribe weights/<stem>_paddle)

Cuatro argumentos están fijados, no simplemente predeterminados. dynamic debe ser False, batch debe ser 1, simplify debe ser True para obtener un grafo de conversión completamente estático, y opset debe ser 15, que es el techo que acepta X2Paddle 1.6.0. Pasar cualquier otra cosa lanza un error antes del trazado.

Sobre el grafo intermedio corre una única normalización. ONNX define como uno la dilatación omitida de un MaxPool, PyTorch escribe el atributo explícito de todo unos y X2Paddle 1.6.0 lo rechaza, así que el exportador elimina ese valor por defecto redundante y deja la operación especificada sin cambios.

El artefacto es un directorio: model.pdmodel, model.pdiparams y metadata.yaml. El Python que X2Paddle genera durante la conversión no forma parte de él.

Ejecutar el artefacto

A través de LibreYOLO
from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("weights/LibreYOLO9t_paddle", device="cpu")result = model.predict(SAMPLE_IMAGE)print(result.boxes.xyxy[:3])
CLI
libreyolo predict --model weights/LibreYOLO9t_paddle \  --source https://raw.githubusercontent.com/LibreYOLO/libreyolo/release/libreyolo/assets/parkour.jpg --device cpu --save
El backend directamente
from libreyolo.backends.paddle import PaddleBackend # Lo que construye LibreYOLO() para un directorio Paddle. El mismo objeto# Results, sin enrutado de la factoría por medio.backend = PaddleBackend("weights/LibreYOLO9t_paddle", device="cpu")result = backend.predict("parkour.jpg")print(result.boxes.xyxy[:3])
Paddle a secas
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"]) # El preprocesado y el postprocesado corren de tu cuenta en esta ruta.

LibreYOLO() reconoce cualquier directorio que contenga a la vez model.pdmodel y model.pdiparams, lee metadata.yaml y devuelve el mismo objeto Results que el checkpoint. Un dispositivo que no sea auto o cpu lanza un error: este backend es solo para CPU.

Lo que construye la factoría es PaddleBackend, exportado desde libreyolo e importable como libreyolo.backends.paddle.PaddleBackend. Constrúyelo tú mismo cuando quieras el backend sin el enrutado por sufijo de la factoría, por ejemplo para pasar task= de forma explícita en un directorio cuyo metadata.yaml no has escrito tú. Su predict() acepta las mismas fuentes y devuelve los mismos resultados.

El snippet del runtime a secas refleja lo que configura el backend, y las tres opciones desactivadas son deliberadas. El pipeline de fusión en CPU de Paddle 2.6 puede caerse mientras optimiza los grandes grafos de gather y scatter que se emiten para la atención deformable, así que el grafo estático portable y sin fusionar es aquel contra el que se midió la paridad. El preprocesado, el decodificado, el NMS y el reescalado de coordenadas corren de tu cuenta en esa ruta.

Restricciones

Sin formas dinámicas, sin FP16, sin INT8, sin NMS embebido, sin runtime en GPU.

Las combinaciones validadas son la detección YOLO9, la detección YOLO9-E2E y YOLO9-P2, la detección, la pose y la segmentación EC, la detección RT-DETRv4, D-FINE, DEIM y DEIMv2, y la detección y la pose YOLO-NAS. Cada una está cubierta por la conversión, una recarga en el runtime de CPU, la paridad de salidas en crudo y resultados públicos reproducidos.

Bloqueadas, con el motivo registrado por combinación:

CombinaciónMotivo
RF-DETR, todas las tareasNecesita ONNX opset 17 y GridSample; X2Paddle 1.6.0 acepta opset 15 o inferior y no tiene mapper de GridSample
Detección RT-DETR y RT-DETRv2Los grafos entrenados necesitan GridSample con opset 16 o superior
Segmentación D-FINEConvierte y recarga, pero el error RMS relativo de los logits de máscara es del 3.52% y el IoU mínimo de máscaras emparejadas es 0.582
Segmentación YOLO9YOLO9 es solo detección en LibreYOLO
Segmentación RTMDet-InsEl decodificado de máscaras con kernel dinámico no tiene contrato de runtime exportado

Cualquier cosa que no aparezca como validada o bloqueada se rechaza con la nota de que no se ha validado a través de la ruta de conversión de ONNX a Paddle.

Para la rejilla completa de familias y tareas, consulta la matriz de exportación. Para una sola combinación:

Comprobar una familia y una tarea antes de exportar
libreyolo formats --family yolo9 --task detect

Leído de libreyolo/export/paddle.py, libreyolo/export/exporter.py, libreyolo/export/support.py, libreyolo/backends/paddle.py, docs/paddle.md y pyproject.toml en la rama dev.