EdgeCrafter

Un transformer de vision compact pour la prédiction dense sur matériel edge, publié en amont sous la forme de trois modèles frères : ECDet, ECPose et ECSeg. LibreYOLO charge les trois comme une seule famille, la tâche étant portée par le checkpoint.

Tâches
detection, pose, instance segmentation
Tailles
s, m, l, x at 640 px
Installer
pip install libreyolo
Niveau de support
Cœur, depuis v1.2.0. Détecteurs entraînables du cœur : les fonctionnalités suivent les fers de lance dans la même vague de publication.
Origine
EdgeCrafter par Intellindust AI Lab, Apache-2.0 original COCO weights; restricted obj2coco weights. Article, source
Licences
Code Apache-2.0, poids Apache-2.0 original COCO weights; restricted obj2coco weights. Usage commercial

Installation

EdgeCrafter ne demande aucun extra optionnel. Tout ce qu'il importe fait partie de l'installation de base.

bash
pip install libreyolo

Le fine-tuning par adaptateurs avec lora=True fait exception, et demande l'extra lora.

bash
pip install "libreyolo[lora]"

Prédire

Les poids sont téléchargés depuis Hugging Face au premier usage, puis mis en cache localement.

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 # Le suffixe -pose du nom de fichier sélectionne la tête de points# clés, aucun argument task n'est donc nécessaire ici.model = LibreYOLO("LibreECs-pose.pt")result = model(SAMPLE_IMAGE, save=True) print(result.keypoints.xy)print(result.boxes.conf)
Segmentation d'instances
from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("LibreECs-seg.pt")result = model(SAMPLE_IMAGE, save=True) print(result.masks.data.shape)

La tâche vient du nom de fichier, si bien qu'un checkpoint -pose ou -seg sélectionne sa propre tête et ne prend aucun argument task. Les trois renvoient l'objet Results que renvoie chaque famille, avec result.keypoints en plus pour la pose et result.masks pour la segmentation. La pose couvre une seule classe, la personne, avec les 17 points clés COCO, et ce nombre est fixé à la construction du modèle. Elle n'a pas de tête de boîtes, si bien que chaque boîte de pose est l'étendue englobante de ses propres points clés, et le troisième canal de point clé est une constante plutôt qu'un score par point.

conf et max_det filtrent la sélection des queries ; iou est accepté par parité d'API mais n'a aucun effet, car les trois têtes décodent un ensemble de queries sans étape de NMS. Voir la prédiction pour les sources, le streaming et le traitement des résultats.

La prédiction de détection accepte une valeur rectangulaire imgsz=(height, width) ; l'entraînement et l'export conservent leurs propres contraintes de forme.

Variantes

Quatre tailles. Elles tournent toutes à la même résolution d'entrée, la table les sépare donc par nombre de paramètres et par exactitude.

CheckpointEntrée (px)mAP 50-95Paramètres (M)
LibreECl64060.132.97
LibreECm64058.419.43
LibreECs64054.39.88
LibreECx64061.149.94

COCO val2017, 500 images. Mesuré par le banc de benchmark de LibreYOLO et publié sur Vision Analysis, où sont comparées la latence selon le matériel et les runtimes et où sont conservés les enregistrements complets des exécutions.

En amont, ECDet, ECPose et ECSeg sont publiés comme trois modèles distincts plutôt que comme un seul modèle à trois têtes. Ils partagent le backbone ECViT et l'encodeur hybride et ne diffèrent que par la tête, si bien que LibreYOLO les réunit en une seule famille et laisse le nom de fichier du checkpoint porter la tâche. Une lettre de taille désigne donc le même backbone et le même encodeur pour les trois, et la prédiction, la validation et l'export prennent les mêmes arguments quel que soit celui que vous chargez.

Entraîner

Les trois tâches s'entraînent via train(), qui lit la tâche depuis le checkpoint chargé et choisit l'entraîneur correspondant.

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 # Demande un dataset de points clés à une seule classe dont le data.yaml# déclare kpt_shape, et imgsz à la taille native du checkpoint.model = LibreYOLO("LibreECs-pose.pt")model.train(    data="my-pose-dataset.yaml",    epochs=50,    imgsz=640,)
Segmentation d'instances
from libreyolo import LibreYOLO # Demande des étiquettes polygonales, et imgsz à la taille native du modèle.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,)

Ce qui a été vérifié pour la détection et la segmentation : la parité d'inférence avec l'amont à 1e-5, couche par couche et par taille, et le fait que la loss et un unique pas d'entraînement s'exécutent sur une entrée synthétique. Ce qui ne l'a pas été, d'après la docstring de train() elle-même : la convergence d'un fine-tuning complet, l'entraînement multi-GPU, l'étape d'arrêt de l'augmentation avec rechargement du meilleur modèle, et le remap des classes d'Objects365 vers COCO. La voie pose suit la recette publiée de DETRPose, un matcher hongrois sur des coûts de classe, de L1 sur les points clés et d'OKS, avec débruitage contrastif des points clés, et sa convergence n'a pas non plus été vérifiée de bout en bout.

Laissé à ses réglages par défaut, l'entraîneur fait 74 époques à lr0=5e-4 avec la précision mixte activée, en suivant la recette amont : AdamW, un schedule cosinus plat, une EMA à 0.9999 et des entrées normalisées ImageNet. La pose et la segmentation exigent toutes deux imgsz à la taille native du checkpoint, car leur grille d'ancres d'évaluation est construite à la construction du modèle ; une autre valeur lève une erreur avant le démarrage du run. La pose demande en plus un dataset à une seule classe dont le data.yaml déclare kpt_shape, avec un nombre de points clés correspondant à la tête.

lora=True ne s'applique qu'à la détection ; la pose et la segmentation lèvent une ValueError dessus. Sur Apple silicon, l'entraîneur garde le run sur le GPU et envoie une seule opération sur CPU, la passe arrière du grid-sample à l'intérieur de l'attention déformable, que PyTorch n'implémente pas en Metal.

Voir l'entraînement pour les datasets, l'augmentation, le multi-GPU et les loggers.

Valider

val() renvoie un dictionnaire indexé par nom de métrique, et affiche les résultats par classe tant que verbose reste actif.

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"])
Segmentation d'instances
from libreyolo import LibreYOLO model = LibreYOLO("LibreECs-seg.pt")metrics = model.val(data="my-dataset.yaml") print(metrics["metrics/mAP50-95(M)"])   # masquesprint(metrics["metrics/mAP50-95(B)"])   # boîtes

La pose reporte les métriques OKS des points clés sous metrics/keypoints_*. La segmentation reporte les masques sous la clé metrics/mAP50-95 sans suffixe et reprend les deux vues en une seule passe, les boîtes sous (B) et les masques sous (M).

Exporter

TâcheONNXTorchScriptExecuTorchTensorRTOpenVINOPaddleMNNRKNNncnnTFLiteCoreMLCore AI
DetectionDetection to ONNX : pris en chargeDetection to TorchScript : pris en chargeDetection to ExecuTorch : pris en chargeDetection to TensorRT : pris en chargeDetection to OpenVINO : pris en chargeDetection to Paddle : pris en chargeDetection to MNN : pris en chargeDetection to RKNN : non pris en chargeDetection to ncnn : non pris en chargeDetection to TFLite : non pris en chargeDetection to CoreML : non pris en chargeDetection to Core AI : pris en charge
PosePose to ONNX : pris en chargePose to TorchScript : pris en chargePose to ExecuTorch : pris en chargePose to TensorRT : pris en chargePose to OpenVINO : pris en chargePose to Paddle : pris en chargePose to MNN : non pris en chargePose to RKNN : non pris en chargePose to ncnn : non pris en chargePose to TFLite : non pris en chargePose to CoreML : non pris en chargePose to Core AI : non pris en charge
Instance segmentationInstance segmentation to ONNX : pris en chargeInstance segmentation to TorchScript : pris en chargeInstance segmentation to ExecuTorch : pris en chargeInstance segmentation to TensorRT : pris en chargeInstance segmentation to OpenVINO : pris en chargeInstance segmentation to Paddle : pris en chargeInstance segmentation to MNN : non pris en chargeInstance segmentation to RKNN : non pris en chargeInstance segmentation to ncnn : non pris en chargeInstance segmentation to TFLite : non pris en chargeInstance segmentation to CoreML : non pris en chargeInstance segmentation to Core AI : non pris en charge

Un artefact exporté se recharge via LibreYOLO() selon son extension de fichier, si bien qu'un fichier .onnx ou .engine se comporte comme un checkpoint et renvoie le même Results. La pose et la segmentation exportent avec une entrée fixe de 640 par 640 plutôt qu'en formes dynamiques, et plusieurs cibles de détection sont elles aussi à canevas fixe, dont OpenVINO, Paddle, MNN, ExecuTorch et Core AI. L'export liste les arguments que chaque format accepte, ainsi que les extras que quelques-uns ajoutent.

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
Utiliser le fichier exporté
from libreyolo import LibreYOLO, SAMPLE_IMAGE # La factory route selon l'extension du fichier, donc un artefact exporté# se charge comme tout checkpoint et renvoie le même objet Results.model = LibreYOLO("LibreECs.onnx")result = model(SAMPLE_IMAGE) print(result.boxes.xyxy)

Entrées et sorties ONNX

Tenseurimages float32 [batch, 3, height, width]
CouleurRGB
Mise à l'échellepixel / 255
Normalisationmoyenne [0.485,0.456,0.406], écart type [0.229,0.224,0.225]
Redimensionnementétirer à largeur x hauteur (sans remplissage, le rapport d'aspect n'est pas conservé), Pillow bilinear
Comment reproduire le redimensionnement bilinéaire de Pillow

LibreYOLO redimensionne avec le filtre BILINEAR de Pillow (Image.resize). Ce n'est ni OpenCV INTER_LINEAR ni INTER_AREA : en réduction, Pillow élargit le filtre du facteur de réduction, et les redimensionnements d'OpenCV modifient les détections et déplacent les boîtes de plusieurs pixels. Pour le reproduire sans Pillow, redimensionnez un axe, arrondissez sur 8 bits, puis redimensionnez l'autre axe et arrondissez de nouveau. Par axe, posons s = in_size / out_size et f = max(s, 1). Le pixel de sortie i a pour centre c = (i + 0.5) * s et lit les pixels source j de int(c - f + 0.5) à int(c + f + 0.5) - 1, limités à l'image, chacun avec le poids max(0, 1 - |j + 0.5 - c| / f), divisé par la somme des poids. Pillow calcule en virgule fixe et choisit l'ordre des axes selon la forme de l'image, donc des poids en virgule flottante peuvent s'en écarter d'un niveau sur quelques pixels. Cela ne change pas les résultats dans nos vérifications.

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, export par défaut
SortieFormeSignification
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.

Post-traitement

  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, export par défaut
SortieFormeSignification
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.

Post-traitement

  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, export par défaut
SortieFormeSignification
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.

Post-traitement

  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.

Pour vérifier votre propre implémentation, passez le même fichier dans LibreYOLO : LibreYOLO("model.onnx").predict("image.jpg") renvoie les résultats de référence. Vérifié avec LibreYOLO 1.7.0.

Checkpoints

Tous les fichiers de poids publiés de cette famille.

Tous les fichiers ci-dessus sont actuellement disponibles dans l<link>organisation LibreYOLO</link> et sont téléchargés à la première utilisation.

Les variantes obj2coco couvrent la détection, la segmentation et la pose. Leur téléchargement exige votre accord et leurs conditions d'amont restreignent l'utilisation commerciale. Les checkpoints COCO originaux conservent leur licence Apache-2.0 enregistrée.

Licence

Vérifiez la licence dans le dépôt Hugging Face des poids précis que vous téléchargez. Chaque checkpoint de l<link>organisation LibreYOLO</link> en possède une, et elles ne sont pas toujours identiques au sein dune même famille. Ce dépôt fait autorité ; le résumé ci-dessous décrit les conditions applicables lors de la dernière vérification de cette page.

Ceci décrit les licences concernées et ne constitue pas un conseil juridique. Si la réponse a une importance commerciale, lisez vous-même les licences et consultez votre propre avocat.

Travail d'origine
EdgeCrafter, Intellindust AI Lab
Licence du projet d'origine
Apache-2.0 original COCO weights; restricted obj2coco weights
Code de LibreYOLO
MIT
Poids
Apache-2.0 original COCO weights; restricted obj2coco weights, republiés sur huggingface.co/LibreYOLO
Interprétation
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.

Citation

@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}
}

Copié depuis le bloc de citation des auteurs sur github.com/Intellindust-AI-Lab/EdgeCrafter#-citation.

Vérifié avec LibreYOLO v1.6.0. Les tableaux de support, les checkpoints et les chiffres de benchmark de cette page sont générés à partir de la bibliothèque publiée et des poids publiés, et non rédigés à la main.