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.
pip install libreyoloLe fine-tuning par adaptateurs avec lora=True fait exception, et demande
l'extra lora.
pip install "libreyolo[lora]"Prédire
Les poids sont téléchargés depuis Hugging Face au premier usage, puis mis en cache localement.
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 # 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)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.
| Checkpoint | Entrée (px) | mAP 50-95 | Paramètres (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. 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.
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 # 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,)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,)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.
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)"]) # masquesprint(metrics["metrics/mAP50-95(B)"]) # boîtesLa 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âche | ONNX | TorchScript | ExecuTorch | TensorRT | OpenVINO | Paddle | MNN | RKNN | ncnn | TFLite | CoreML | Core AI |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Detection | Detection to ONNX : pris en charge | Detection to TorchScript : pris en charge | Detection to ExecuTorch : pris en charge | Detection to TensorRT : pris en charge | Detection to OpenVINO : pris en charge | Detection to Paddle : pris en charge | Detection to MNN : pris en charge | Detection to RKNN : non pris en charge | Detection to ncnn : non pris en charge | Detection to TFLite : non pris en charge | Detection to CoreML : non pris en charge | Detection to Core AI : pris en charge |
| Pose | Pose to ONNX : pris en charge | Pose to TorchScript : pris en charge | Pose to ExecuTorch : pris en charge | Pose to TensorRT : pris en charge | Pose to OpenVINO : pris en charge | Pose to Paddle : pris en charge | Pose to MNN : non pris en charge | Pose to RKNN : non pris en charge | Pose to ncnn : non pris en charge | Pose to TFLite : non pris en charge | Pose to CoreML : non pris en charge | Pose to Core AI : non pris en charge |
| Instance segmentation | Instance segmentation to ONNX : pris en charge | Instance segmentation to TorchScript : pris en charge | Instance segmentation to ExecuTorch : pris en charge | Instance segmentation to TensorRT : pris en charge | Instance segmentation to OpenVINO : pris en charge | Instance segmentation to Paddle : pris en charge | Instance segmentation to MNN : non pris en charge | Instance segmentation to RKNN : non pris en charge | Instance segmentation to ncnn : non pris en charge | Instance segmentation to TFLite : non pris en charge | Instance segmentation to CoreML : non pris en charge | Instance 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.
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 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
| Tenseur | images float32 [batch, 3, height, width] |
|---|---|
| Couleur | RGB |
| Mise à l'échelle | pixel / 255 |
| Normalisation | moyenne [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
| Sortie | Forme | Signification |
|---|---|---|
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
- 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, export par défaut
| Sortie | Forme | Signification |
|---|---|---|
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
- 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, export par défaut
| Sortie | Forme | Signification |
|---|---|---|
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
- 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.
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.
| Fichier | Entrée (px) | Licence des poids |
|---|---|---|
| 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 | |
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
- Source du projet d'origine
- github.com/Intellindust-AI-Lab/EdgeCrafter
- 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.