EdgeCrafter

Un vision transformer compacto para predicción densa en hardware edge, publicado upstream como tres modelos hermanos: ECDet, ECPose y ECSeg. LibreYOLO carga los tres como una sola familia, con la tarea determinada por el checkpoint.

Tareas
detection, pose, instance segmentation
Tamaños
s, m, l, x at 640 px
Instalación
pip install libreyolo
Nivel de compatibilidad
Núcleo, desde v1.2.0. Detectores entrenables del núcleo: las funciones siguen a los modelos emblemáticos en la misma oleada de versiones.
Proyecto original
EdgeCrafter de Intellindust AI Lab, Apache-2.0 original COCO weights; restricted obj2coco weights. Artículo, fuente
Licencias
Código Apache-2.0, pesos Apache-2.0 original COCO weights; restricted obj2coco weights. Uso comercial

Instalación

EdgeCrafter no necesita ningún extra opcional. Todo lo que importa está en la instalación base.

bash
pip install libreyolo

El fine-tuning con adaptadores mediante lora=True es la excepción, y necesita el extra lora.

bash
pip install "libreyolo[lora]"

Predicción

Los pesos se descargan de Hugging Face en el primer uso y se guardan en la caché local.

Python
from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("LibreECs.pt")result = model(SAMPLE_IMAGE, save=True) for box in result.boxes:    print(box.cls, box.conf, box.xyxy)
CLI
libreyolo predict model=LibreECs.pt source=https://raw.githubusercontent.com/LibreYOLO/libreyolo/release/libreyolo/assets/parkour.jpg save=True
Pose
from libreyolo import LibreYOLO, SAMPLE_IMAGE # El sufijo -pose del nombre de archivo selecciona la cabeza de# keypoints, así que aquí no hace falta argumento de tarea.model = LibreYOLO("LibreECs-pose.pt")result = model(SAMPLE_IMAGE, save=True) print(result.keypoints.xy)print(result.boxes.conf)
Segmentación de instancias
from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("LibreECs-seg.pt")result = model(SAMPLE_IMAGE, save=True) print(result.masks.data.shape)

La tarea viene del nombre del archivo, así que un checkpoint -pose o -seg selecciona su propia cabeza y no acepta ningún argumento de tarea. Los tres devuelven el objeto Results que devuelven todas las familias, con result.keypoints añadido para pose y result.masks para segmentación. Pose cubre una sola clase, persona, con los 17 keypoints de COCO, y el número queda fijado al construir el modelo. No tiene cabeza de boxes, así que cada box de pose es la extensión que envuelve a sus propios keypoints, y el tercer canal del keypoint es una constante en lugar de una puntuación por punto.

conf y max_det filtran la selección de queries; iou se acepta por paridad de API pero no tiene efecto, porque las tres cabezas decodifican un conjunto de queries sin paso de NMS. Consulta predicción para fuentes, streaming y manejo de resultados.

La predicción de detección acepta un imgsz=(height, width) rectangular; el entrenamiento y la exportación mantienen sus propias restricciones de forma.

Variantes

Cuatro tamaños. Todos funcionan a la misma resolución de entrada, así que la tabla los separa por número de parámetros y precisión.

CheckpointEntrada (px)mAP 50-95Parámetros (M)
LibreECl64060.132.97
LibreECm64058.419.43
LibreECs64054.39.88
LibreECx64061.149.94

COCO val2017, 500 images. Medido con el sistema de benchmarks de LibreYOLO y publicado en Vision Analysis, donde se comparan la latencia entre distintos hardwares y runtimes y se conservan los registros completos de las ejecuciones.

Upstream publica ECDet, ECPose y ECSeg como tres modelos separados en lugar de un modelo con tres cabezas. Comparten el backbone ECViT y el encoder híbrido y solo se diferencian en la cabeza, así que LibreYOLO los agrupa en una sola familia y deja que el nombre del archivo del checkpoint indique la tarea. Por tanto, una letra de tamaño significa el mismo backbone y el mismo encoder en los tres, y predicción, validación y exportación aceptan los mismos argumentos sea cual sea el que cargues.

Entrenamiento

Las tres tareas se entrenan con train(), que lee la tarea del checkpoint cargado y elige el trainer correspondiente.

Python
from libreyolo import LibreYOLO model = LibreYOLO("LibreECs.pt")model.train(    data="my-dataset.yaml",    epochs=50,    imgsz=640,    batch=8,    lr0=5e-4,)
CLI
libreyolo train model=LibreECs.pt data=my-dataset.yaml epochs=50 imgsz=640 batch=8 lr0=5e-4
Pose
from libreyolo import LibreYOLO # Necesita un dataset de keypoints de una sola clase cuyo data.yaml# declare kpt_shape, e imgsz al tamaño nativo del checkpoint.model = LibreYOLO("LibreECs-pose.pt")model.train(    data="my-pose-dataset.yaml",    epochs=50,    imgsz=640,)
Segmentación de instancias
from libreyolo import LibreYOLO # Necesita etiquetas de polígonos, e imgsz al tamaño nativo del checkpoint.model = LibreYOLO("LibreECs-seg.pt")model.train(    data="my-dataset.yaml",    epochs=50,    imgsz=640,)
LoRA
from libreyolo import LibreYOLO model = LibreYOLO("LibreECs.pt")model.train(    data="my-dataset.yaml",    epochs=50,    lora=True,)

Lo que sí se ha comprobado para detección y segmentación: paridad de inferencia con upstream a 1e-5, capa a capa y por tamaño, y que la loss (la función de pérdida) y un único paso de entrenamiento se ejecutan sobre entrada sintética. Lo que no, según el propio docstring de train(): la convergencia de un fine-tune completo, el entrenamiento multi-GPU, el paso de recarga del mejor checkpoint al detener el aumento de datos, y el remapeo de clases de Objects365 a COCO. La ruta de pose sigue la receta publicada de DETRPose, un matcher húngaro sobre costes de clase, L1 de keypoints y OKS con denoising contrastivo de keypoints, y su convergencia tampoco se ha comprobado de extremo a extremo.

Si no lo tocas, el trainer ejecuta 74 epochs con lr0=5e-4 y precisión mixta activada, siguiendo la receta de upstream: AdamW, un schedule coseno plano, EMA a 0.9999 y entradas normalizadas según ImageNet. Pose y segmentación requieren ambas imgsz al tamaño nativo del checkpoint, porque su rejilla de anclas de evaluación se construye al construir el modelo; un valor distinto lanza un error antes de que empiece la ejecución. Pose además requiere un dataset de una sola clase cuyo data.yaml declare kpt_shape, con un número de keypoints que coincida con el de la cabeza.

lora=True solo se aplica a detección; pose y segmentación lanzan un ValueError con él. En Apple silicon el trainer mantiene la ejecución en la GPU y envía una operación a CPU, el backward de grid-sample dentro de la atención deformable, que PyTorch no implementa en Metal.

Consulta entrenamiento para datasets, aumento de datos, multi-GPU y loggers.

Validación

val() devuelve un diccionario indexado por nombre de métrica, e imprime resultados por clase si dejas verbose activado.

Python
from libreyolo import LibreYOLO model = LibreYOLO("LibreECs.pt")metrics = model.val(data="my-dataset.yaml") print(metrics["metrics/mAP50-95"])print(metrics["metrics/mAP50"])
CLI
libreyolo val model=LibreECs.pt data=my-dataset.yaml
Pose
from libreyolo import LibreYOLO model = LibreYOLO("LibreECs-pose.pt")metrics = model.val(data="my-pose-dataset.yaml") print(metrics["metrics/keypoints_mAP50-95"])print(metrics["metrics/keypoints_mAP50"])
Segmentación de instancias
from libreyolo import LibreYOLO model = LibreYOLO("LibreECs-seg.pt")metrics = model.val(data="my-dataset.yaml") print(metrics["metrics/mAP50-95(M)"])   # máscarasprint(metrics["metrics/mAP50-95(B)"])   # boxes

Pose reporta métricas OKS de keypoints bajo metrics/keypoints_*. Segmentación reporta las máscaras bajo la clave metrics/mAP50-95 a secas y repite ambas vistas en una sola pasada, los boxes bajo (B) y las máscaras bajo (M).

Exportación

TareaONNXTorchScriptExecuTorchTensorRTOpenVINOPaddleMNNRKNNncnnTFLiteCoreMLCore AI
DetectionDetection to ONNX: compatibleDetection to TorchScript: compatibleDetection to ExecuTorch: compatibleDetection to TensorRT: compatibleDetection to OpenVINO: compatibleDetection to Paddle: compatibleDetection to MNN: compatibleDetection to RKNN: no compatibleDetection to ncnn: no compatibleDetection to TFLite: no compatibleDetection to CoreML: no compatibleDetection to Core AI: compatible
PosePose to ONNX: compatiblePose to TorchScript: compatiblePose to ExecuTorch: compatiblePose to TensorRT: compatiblePose to OpenVINO: compatiblePose to Paddle: compatiblePose to MNN: no compatiblePose to RKNN: no compatiblePose to ncnn: no compatiblePose to TFLite: no compatiblePose to CoreML: no compatiblePose to Core AI: no compatible
Instance segmentationInstance segmentation to ONNX: compatibleInstance segmentation to TorchScript: compatibleInstance segmentation to ExecuTorch: compatibleInstance segmentation to TensorRT: compatibleInstance segmentation to OpenVINO: compatibleInstance segmentation to Paddle: compatibleInstance segmentation to MNN: no compatibleInstance segmentation to RKNN: no compatibleInstance segmentation to ncnn: no compatibleInstance segmentation to TFLite: no compatibleInstance segmentation to CoreML: no compatibleInstance segmentation to Core AI: no compatible

Un artefacto exportado se vuelve a cargar con LibreYOLO() según su extensión de archivo, así que un archivo .onnx o .engine se comporta como un checkpoint y devuelve el mismo Results. Pose y segmentación se exportan con una entrada fija de 640 por 640 en lugar de formas dinámicas, y varios destinos de detección también tienen lienzo fijo, incluidos OpenVINO, Paddle, MNN, ExecuTorch y Core AI. Exportación lista los argumentos que acepta cada formato y los extras que añaden unos pocos.

Python
from libreyolo import LibreYOLO model = LibreYOLO("LibreECs.pt")model.export(format="onnx", imgsz=640)model.export(format="tensorrt", imgsz=640, half=True)
CLI
libreyolo export model=LibreECs.pt format=onnx imgsz=640libreyolo export model=LibreECs-pose.pt format=onnx imgsz=640libreyolo export model=LibreECs-seg.pt format=onnx imgsz=640
Usar el archivo exportado
from libreyolo import LibreYOLO, SAMPLE_IMAGE # La factoría enruta según la extensión del archivo, así que un artefacto# exportado se carga como cualquier checkpoint y devuelve el mismo Results.model = LibreYOLO("LibreECs.onnx")result = model(SAMPLE_IMAGE) print(result.boxes.xyxy)

Entradas y salidas ONNX

Tensorimages float32 [batch, 3, height, width]
ColorRGB
Escaladopíxel / 255
Normalizaciónmedia [0.485,0.456,0.406], desviación típica [0.229,0.224,0.225]
Redimensionadoestirar a ancho x alto (sin relleno, no se conserva la relación de aspecto), Pillow bilinear
Cómo reproducir el redimensionado bilineal de Pillow

LibreYOLO redimensiona con el filtro BILINEAR de Pillow (Image.resize). No es OpenCV INTER_LINEAR ni INTER_AREA: al reducir, Pillow ensancha el filtro según el factor de reducción, y los redimensionados de OpenCV cambian las detecciones y desplazan las cajas varios píxeles. Para reproducirlo sin Pillow, redimensiona un eje, redondea a 8 bits, luego redimensiona el otro eje y vuelve a redondear. Por eje, sea s = in_size / out_size y f = max(s, 1). El píxel de salida i tiene centro c = (i + 0.5) * s y lee los píxeles de origen j desde int(c - f + 0.5) hasta int(c + f + 0.5) - 1, recortados a la imagen, cada uno con peso max(0, 1 - |j + 0.5 - c| / f), dividido por la suma de los pesos. Pillow trabaja en coma fija y elige el orden de los ejes según la forma de la imagen, así que los pesos en coma flotante pueden diferir en un nivel en unos pocos píxeles. Eso no cambia los resultados en nuestras comprobaciones.

Square input only. Export rejects a non-square imgsz, and height and width are 640 by default.

Detect and segment: batch size 1 only. The graph declares a dynamic batch axis, but batches of 2 or more fail in 1.7.0. Pose runs with any batch size.

For a bit-exact match, use Pillow's integer math: multiply each weight by 2^22 and round half away from zero, sum weight x pixel in integers, add 2^21, shift right by 22 and clip to 0 to 255.

Divide by 255 after the resize, then subtract the ImageNet mean and divide by the ImageNet std per channel.

Detection, exportación por defecto
SalidaFormaSignificado
pred_logits[batch, queries, nc]Raw class logits per query, sigmoid not applied. 300 queries and 80 classes for the COCO checkpoints.
pred_boxes[batch, queries, 4]Boxes as cx, cy, w, h, normalized 0 to 1 of the input.

Posprocesado

  1. Apply sigmoid to pred_logits.
  2. Flatten the scores to queries x nc and take the top max_det (300 by default) over all queries x classes. For flat index k, the query is k // nc and the class is k % nc. One query can yield several classes.
  3. Keep the entries whose score is strictly above the confidence threshold (0.25 by default). There is no NMS.
  4. Convert the query's box to x1, y1, x2, y2 with x1 = cx - w / 2, y1 = cy - h / 2, x2 = cx + w / 2, y2 = cy + h / 2.
  5. Map boxes back to the original image: multiply x by the original width and y by the original height. The input was stretched, so no pad offset applies. LibreYOLO does not clip these boxes to the image.
  6. nms=True is not available for this family: export raises NotImplementedError.
Instance segmentation, exportación por defecto
SalidaFormaSignificado
pred_logits[batch, queries, nc]Raw class logits per query, sigmoid not applied. 300 queries and 80 classes for the COCO checkpoints.
pred_boxes[batch, queries, 4]Boxes as cx, cy, w, h, normalized 0 to 1 of the input.
pred_masks[batch, queries, mask_h, mask_w]Raw mask logits per query over the whole input canvas, sigmoid not applied. mask_h and mask_w are a quarter of the input, 160 x 160 at 640 x 640.

Posprocesado

  1. Select detections exactly as for detect: sigmoid on pred_logits, top max_det (300 by default) over all queries x classes, keep scores strictly above the confidence threshold (0.25 by default). There is no NMS.
  2. Convert and map the boxes as for detect: cx, cy, w, h to x1, y1, x2, y2, then multiply x by the original width and y by the original height. LibreYOLO does not clip these boxes to the image.
  3. For each kept detection, take the mask logits of its query and resize them straight to the original image size with bilinear interpolation, half-pixel centers (align_corners=False) and no antialiasing. cv2.resize with INTER_LINEAR on float32 does this.
  4. The mask is the pixels whose resized logit is above 0. Masks are not cropped to the box.
  5. nms=True is not available for this family: export raises NotImplementedError.
Pose, exportación por defecto
SalidaFormaSignificado
pred_logits[batch, queries, 2]Raw logits per query, sigmoid not applied. 60 queries. Index 1, the last one, is the person class. Index 0 is an unused slot.
pred_keypoints[batch, queries, num_keypoints * 2]Keypoints as x0, y0, x1, y1 and so on, normalized 0 to 1 of the input. num_keypoints is 17 (COCO order) and is recorded in the num_keypoints metadata key. There is no box output and no keypoint visibility or confidence.

Posprocesado

  1. Apply sigmoid to the last logit of each query. That is the person score.
  2. Sort the queries by score, highest first, and keep at most max_det (300 by default, so all 60 queries). Keep the queries whose score is at or above the confidence threshold (0.25 by default). Note at or above here, strictly above for detect and segment. There is no NMS.
  3. Reshape each kept query's keypoints to [num_keypoints, 2]. Map them back to the original image: multiply x by the original width and y by the original height.
  4. The box is the extent of the mapped keypoints: x1, y1 are the minimum x and y, x2, y2 the maximum. The class is always 0 (person).
  5. LibreYOLO reports visibility 1 for every keypoint, since the graph predicts xy only.
  6. nms=True is not available for this family: export raises NotImplementedError.

Para comprobar tu propia implementación, pasa el mismo archivo por LibreYOLO: LibreYOLO("model.onnx").predict("image.jpg") devuelve los resultados de referencia. Verificado con LibreYOLO 1.7.0.

Checkpoints

Todos los archivos de pesos publicados de esta familia.

Todos los archivos anteriores existen hoy en la organización de LibreYOLO y se descargan la primera vez que se usan.

Las variantes obj2coco cubren detección, segmentación y pose. Su descarga requiere aceptación explícita y sus términos upstream restringen el uso comercial. Los checkpoints COCO originales conservan su licencia Apache-2.0 registrada.

Licencia

Comprueba la licencia en el repositorio de Hugging Face de los pesos concretos que descargues. Cada checkpoint de la organización de LibreYOLO incluye una, y no siempre es la misma en toda una familia. Ese repositorio es la fuente autorizada; el resumen siguiente describe qué se aplicaba cuando se verificó esta página por última vez.

Esta es una descripción de las licencias implicadas, no asesoramiento legal. Si la respuesta es importante a nivel comercial, lee las licencias y busca tu propio asesoramiento.

Trabajo original
EdgeCrafter, Intellindust AI Lab
Licencia del proyecto original
Apache-2.0 original COCO weights; restricted obj2coco weights
Fuente del proyecto original
github.com/Intellindust-AI-Lab/EdgeCrafter
Código de LibreYOLO
MIT
Pesos
Apache-2.0 original COCO weights; restricted obj2coco weights, republicados en huggingface.co/LibreYOLO
Interpretación
Original COCO checkpoints retain their recorded Apache-2.0 grant. The obj2coco detection, segmentation and pose variants require explicit opt-in and retain non-commercial upstream terms. The library code license does not replace those weight terms.

Cita

@article{liu2026edgecrafter,
  title={EdgeCrafter: Compact ViTs for Edge Dense Prediction via Task-Specialized Distillation},
  author={Liu, Longfei and Hou, Yongjie and Li, Yang and Wang, Qirui and Sha, Youyang and Yu, Yongjun and Wang, Yinzhi and Ru, Peizhe and Yu, Xuanlong and Shen, Xi},
  journal={arXiv},
  year={2026}
}

Copiado del bloque de cita de los autores en github.com/Intellindust-AI-Lab/EdgeCrafter#-citation.

Verificado con LibreYOLO v1.6.0. Las tablas de compatibilidad, los checkpoints y las cifras de rendimiento de esta página se generan a partir de la biblioteca publicada y los pesos publicados; no se escriben a mano.