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.
pip install libreyoloEl fine-tuning con adaptadores mediante lora=True es la excepción, y necesita
el extra lora.
pip install "libreyolo[lora]"Predicción
Los pesos se descargan de Hugging Face en el primer uso y se guardan en la caché local.
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)libreyolo predict model=LibreECs.pt source=https://raw.githubusercontent.com/LibreYOLO/libreyolo/release/libreyolo/assets/parkour.jpg save=Truefrom 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)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.
| Checkpoint | Entrada (px) | mAP 50-95 | Parámetros (M) |
|---|---|---|---|
| LibreECl | 640 | 60.1 | 32.97 |
| LibreECm | 640 | 58.4 | 19.43 |
| LibreECs | 640 | 54.3 | 9.88 |
| LibreECx | 640 | 61.1 | 49.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.
from libreyolo import LibreYOLO model = LibreYOLO("LibreECs.pt")model.train( data="my-dataset.yaml", epochs=50, imgsz=640, batch=8, lr0=5e-4,)libreyolo train model=LibreECs.pt data=my-dataset.yaml epochs=50 imgsz=640 batch=8 lr0=5e-4from 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,)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,)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.
from libreyolo import LibreYOLO model = LibreYOLO("LibreECs.pt")metrics = model.val(data="my-dataset.yaml") print(metrics["metrics/mAP50-95"])print(metrics["metrics/mAP50"])libreyolo val model=LibreECs.pt data=my-dataset.yamlfrom 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"])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)"]) # boxesPose 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
| Tarea | ONNX | TorchScript | ExecuTorch | TensorRT | OpenVINO | Paddle | MNN | RKNN | ncnn | TFLite | CoreML | Core AI |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Detection | Detection to ONNX: compatible | Detection to TorchScript: compatible | Detection to ExecuTorch: compatible | Detection to TensorRT: compatible | Detection to OpenVINO: compatible | Detection to Paddle: compatible | Detection to MNN: compatible | Detection to RKNN: no compatible | Detection to ncnn: no compatible | Detection to TFLite: no compatible | Detection to CoreML: no compatible | Detection to Core AI: compatible |
| Pose | Pose to ONNX: compatible | Pose to TorchScript: compatible | Pose to ExecuTorch: compatible | Pose to TensorRT: compatible | Pose to OpenVINO: compatible | Pose to Paddle: compatible | Pose to MNN: no compatible | Pose to RKNN: no compatible | Pose to ncnn: no compatible | Pose to TFLite: no compatible | Pose to CoreML: no compatible | Pose to Core AI: no compatible |
| Instance segmentation | Instance segmentation to ONNX: compatible | Instance segmentation to TorchScript: compatible | Instance segmentation to ExecuTorch: compatible | Instance segmentation to TensorRT: compatible | Instance segmentation to OpenVINO: compatible | Instance segmentation to Paddle: compatible | Instance segmentation to MNN: no compatible | Instance segmentation to RKNN: no compatible | Instance segmentation to ncnn: no compatible | Instance segmentation to TFLite: no compatible | Instance segmentation to CoreML: no compatible | Instance 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.
from libreyolo import LibreYOLO model = LibreYOLO("LibreECs.pt")model.export(format="onnx", imgsz=640)model.export(format="tensorrt", imgsz=640, half=True)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=640from 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
| Tensor | images float32 [batch, 3, height, width] |
|---|---|
| Color | RGB |
| Escalado | píxel / 255 |
| Normalización | media [0.485,0.456,0.406], desviación típica [0.229,0.224,0.225] |
| Redimensionado | estirar 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
| Salida | Forma | Significado |
|---|---|---|
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
- Apply sigmoid to pred_logits.
- 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.
- Keep the entries whose score is strictly above the confidence threshold (0.25 by default). There is no NMS.
- 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.
- 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.
- nms=True is not available for this family: export raises NotImplementedError.
Instance segmentation, exportación por defecto
| Salida | Forma | Significado |
|---|---|---|
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
- 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.
- 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.
- 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.
- The mask is the pixels whose resized logit is above 0. Masks are not cropped to the box.
- nms=True is not available for this family: export raises NotImplementedError.
Pose, exportación por defecto
| Salida | Forma | Significado |
|---|---|---|
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
- Apply sigmoid to the last logit of each query. That is the person score.
- 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.
- 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.
- 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).
- LibreYOLO reports visibility 1 for every keypoint, since the graph predicts xy only.
- 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.
| Archivo | Entrada (px) | Licencia de los pesos |
|---|---|---|
| Detection | ||
| LibreECs.pt | 640 | apache-2.0 |
| LibreECm.pt | 640 | apache-2.0 |
| LibreECl.pt | 640 | apache-2.0 |
| LibreECx.pt | 640 | apache-2.0 |
| LibreECl-obj2coco.pt | other | |
| LibreECm-obj2coco.pt | other | |
| LibreECs-obj2coco.pt | other | |
| LibreECx-obj2coco.pt | other | |
| Pose | ||
| LibreECs-pose.pt | 640 | apache-2.0 |
| LibreECm-pose.pt | 640 | apache-2.0 |
| LibreECl-pose.pt | 640 | apache-2.0 |
| LibreECx-pose.pt | 640 | apache-2.0 |
| LibreECl-pose-obj2coco.pt | other | |
| LibreECm-pose-obj2coco.pt | other | |
| LibreECs-pose-obj2coco.pt | other | |
| LibreECx-pose-obj2coco.pt | other | |
| Instance segmentation | ||
| LibreECs-seg.pt | 640 | apache-2.0 |
| LibreECm-seg.pt | 640 | apache-2.0 |
| LibreECl-seg.pt | 640 | apache-2.0 |
| LibreECx-seg.pt | 640 | apache-2.0 |
| LibreECm-seg-obj2coco.pt | other | |
| LibreECs-seg-obj2coco.pt | other | |
| LibreECl-seg-obj2coco.pt | other | |
| LibreECx-seg-obj2coco.pt | other | |
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.