D-FINE
Un transformer de détection qui reformule la régression des boîtes comme une distribution de probabilité sur chaque bord de boîte, affinée au fil des couches du décodeur. LibreYOLO le prend en charge pour la détection et la segmentation d'instances.
- Tâches
- detection, instance segmentation
- Tailles
- n, s, m, l, x at 640 px
- Installer
pip install libreyolo- Niveau de support
- Cœur, depuis v1.1.0. Détecteurs entraînables du cœur : les fonctionnalités suivent les fers de lance dans la même vague de publication.
- Licences
- Code Apache-2.0, poids Apache-2.0. Usage commercial
Installation
D-FINE 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("LibreDFINEn.pt")result = model(SAMPLE_IMAGE, save=True) for box in result.boxes: print(box.cls, box.conf, box.xyxy)libreyolo predict model=LibreDFINEn.pt source=https://raw.githubusercontent.com/LibreYOLO/libreyolo/release/libreyolo/assets/parkour.jpg save=Truefrom libreyolo import LibreYOLO, SAMPLE_IMAGE # Le suffixe -seg du nom de fichier sélectionne la tête de masques,# aucun argument task n'est donc nécessaire ici.model = LibreYOLO("LibreDFINEn-seg.pt")result = model(SAMPLE_IMAGE, save=True) print(result.masks.data.shape)L'objet Results renvoyé est celui que renvoie chaque famille, si bien que
remplacer le détecteur par un autre tient en une seule ligne. Un nom de fichier
en -seg résout de lui-même vers la tâche de segmentation, et result.masks
porte alors les masques d'instances à côté des boîtes. conf et max_det
filtrent la sélection des queries ; iou est accepté par parité d'API mais n'a
aucun effet, car le décodeur est un set predictor sans étape de NMS. Voir
la prédiction pour les sources, le streaming et le traitement
des résultats.
Variantes
Cinq 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) |
|---|---|---|---|
| LibreDFINEl | 640 | 60.0 | 31.24 |
| LibreDFINEm | 640 | 57.8 | 19.59 |
| LibreDFINEn | 640 | 45.8 | 3.78 |
| LibreDFINEs | 640 | 53.4 | 10.32 |
| LibreDFINEx | 640 | 61.4 | 62.62 |
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.
La segmentation réutilise le backbone, l'encodeur et le décodeur de détection et
y ajoute une tête de masques, si bien qu'un checkpoint -seg prend les mêmes
arguments que son homologue de détection. La famille RT-DETRv4 de LibreYOLO est
écrite comme une sous-classe du wrapper D-FINE : elle hérite de cette lignée de
décodeur, puis restreint sa liste de tâches à la seule détection, car elle ne
porte pas de tête de masques.
Entraîner
L'entraînement démarre depuis un checkpoint publié, pour les deux tâches.
from libreyolo import LibreYOLO model = LibreYOLO("LibreDFINEn.pt")model.train(data="my-dataset.yaml", epochs=50, imgsz=640, batch=8, lr0=2e-4)libreyolo train model=LibreDFINEn.pt data=my-dataset.yaml \ epochs=50 imgsz=640 batch=8 lr0=2e-4# Reprend depuis les poids de segmentation publiés, tête de masques incluse.libreyolo train model=LibreDFINEn-seg.pt data=my-dataset.yaml \ task=segment epochs=50 imgsz=640# Les poids de détection n'ont pas de tête de masques, c'est donc un# transfert explicite. La tête démarre non entraînée et n'est utile# qu'une fois entraînée. C'est task=segment qui autorise le transfert.libreyolo train model=LibreDFINEn.pt data=my-dataset.yaml \ task=segment epochs=50 imgsz=640from libreyolo import LibreYOLO model = LibreYOLO("LibreDFINEn.pt")model.train(data="my-dataset.yaml", epochs=50, lora=True)libreyolo train model=LibreDFINEn.pt data=my-dataset.yaml \ epochs=50 device=0,1 batch=16Laissé à ses réglages par défaut, l'entraîneur fait 132 époques à lr0=2e-4
avec amp=True et amp_dtype="float16", un batch de 16 et un early stopping après 50 époques sans
amélioration. libreyolo train part de la même recette pour les deux tâches :
AdamW avec un schedule cosinus plat, weight_decay=1e-4, 2 époques de warmup,
un écrêtage de la norme du gradient à 0.1, et aucune augmentation mosaic, MixUp,
HSV ou affine. Sans name=, ses runs vont dans runs/train/dfine_exp. Les poids de détection sont un point de départ légitime pour un
entraînement de segmentation, mais seulement comme transfert explicite, puisque
la tête de masques démarre non entraînée et renverrait sinon des masques sans
signification. C'est le passage de task=segment à la CLI qui l'autorise. La
voie Python est plus étroite : LibreDFINE doit être construit directement avec
allow_detect_to_segment_transfer=True, car la factory LibreYOLO() n'accepte
pas cet argument, et la construction directe ne télécharge rien, si bien que le
fichier de poids doit déjà être présent sur le disque.
lora=True s'applique à la détection. L'entraînement en segmentation le refuse
et renvoie plutôt vers freeze='backbone', car la tête de masques n'a pas été
testée avec des adaptateurs. Sur Apple silicon, l'entraîneur bascule tout le run
sur CPU : la passe arrière du matmul par bins de l'Integral déclenche un échec de
compilation Metal. L'inférence sur MPS n'est pas concernée.
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("LibreDFINEn.pt")metrics = model.val(data="my-dataset.yaml") print(metrics["metrics/mAP50-95"])print(metrics["metrics/mAP50"])libreyolo val model=LibreDFINEn.pt data=my-dataset.yamlfrom libreyolo import LibreYOLO model = LibreYOLO("LibreDFINEn-seg.pt")metrics = model.val(data="my-dataset.yaml") print(metrics["metrics/mAP50-95(M)"]) # masquesprint(metrics["metrics/mAP50-95(B)"]) # boîtesSur un checkpoint -seg, la clé metrics/mAP50-95 sans suffixe porte le score
des masques, et le même run reporte aussi les boîtes sous (B) et les masques
sous (M), si bien que les deux sont disponibles en une seule passe.
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 : non 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 |
| Instance segmentation | Instance segmentation to ONNX : pris en charge | Instance segmentation to TorchScript : pris en charge | Instance segmentation to ExecuTorch : non pris en charge | Instance segmentation to TensorRT : pris en charge | Instance segmentation to OpenVINO : pris en charge | Instance segmentation to Paddle : non 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. Les voies OpenVINO, Paddle, MNN et
Core AI exportent à taille de canevas fixe plutôt qu'en formes dynamiques.
L'export liste les arguments que chaque format accepte, ainsi
que les extras que quelques-uns ajoutent.
from libreyolo import LibreYOLO model = LibreYOLO("LibreDFINEn.pt")model.export(format="onnx", imgsz=640)model.export(format="tensorrt", imgsz=640, half=True)libreyolo export model=LibreDFINEn.pt format=onnx imgsz=640libreyolo export model=LibreDFINEn.pt format=tensorrt imgsz=640 half=Truefrom libreyolo import LibreYOLO, SAMPLE_IMAGE # La factory route selon l'extension du fichier, donc un artefact exporté# se charge comme un checkpoint et renvoie le même objet Results.model = LibreYOLO("LibreDFINEn.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 | aucune |
| 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.
Batch size 1 only. The graph declares a dynamic batch axis, but batches of 2 or more fail in 1.7.0.
Divide by 255 after the resize. There is no mean or std normalization.
Detection, export par défaut
| Sortie | Forme | Signification |
|---|---|---|
pred_logits | [batch, queries, nc] | One logit per query and class. Sigmoid is not applied. queries is 300 for every size. |
pred_boxes | [batch, queries, 4] | cx, cy, w, h of each query, normalized 0 to 1 of the input. The input is the whole image stretched, so these are also fractions of the original image. |
Post-traitement
- Apply sigmoid to pred_logits.
- Flatten the [queries, nc] scores and take the top 300 (max_det, 300 by default). For flat index k, the query is k // nc and the class is k % nc. One query can yield several classes.
- Keep the pairs whose score is above the confidence threshold (0.25 by default).
- Convert the query's box to x1 = cx - w / 2, y1 = cy - h / 2, x2 = cx + w / 2, y2 = cy + h / 2. Multiply x by the original image width and y by the original image height.
- There is no NMS and the iou threshold is not used. D-FINE predicts a set of boxes, and export with nms=True raises NotImplementedError.
- LibreYOLO does not clip these boxes, so an edge can sit slightly outside the image.
Instance segmentation, export par défaut
| Sortie | Forme | Signification |
|---|---|---|
pred_logits | [batch, queries, nc] | One logit per query and class. Sigmoid is not applied. queries is 300 for every size. |
pred_boxes | [batch, queries, 4] | cx, cy, w, h of each query, normalized 0 to 1 of the input. The input is the whole image stretched, so these are also fractions of the original image. |
pred_masks | [batch, queries, mask_h, mask_w] | One mask per query, sigmoid already applied. mask_h is height / 4 and mask_w is width / 4, 160 x 160 at 640 x 640. |
Post-traitement
- Apply sigmoid to pred_logits.
- Flatten the [queries, nc] scores and take the top 300 (max_det, 300 by default). For flat index k, the query is k // nc and the class is k % nc. One query can yield several classes.
- Keep the pairs whose score is above the confidence threshold (0.25 by default).
- Convert the query's box to x1 = cx - w / 2, y1 = cy - h / 2, x2 = cx + w / 2, y2 = cy + h / 2. Multiply x by the original image width and y by the original image height.
- For each kept pair, take its query's mask. Resize it with bilinear interpolation and half-pixel centers (align_corners=False, no antialiasing) to height x width, then again to the original image size.
- A pixel belongs to the mask when its value is 0.5 or more.
- Clear every mask pixel outside the box. Pixel (x, y) stays only when x1 <= x < x2 and y1 <= y < y2, in original-image pixels.
- There is no NMS and the iou threshold is not used. D-FINE predicts a set of boxes, and export with nms=True raises NotImplementedError.
- LibreYOLO does not clip the boxes of a .pt predict, so an edge can sit slightly outside the image. Its ONNX backend clips them to the image.
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 | ||
| LibreDFINEn.pt | 640 | apache-2.0 |
| LibreDFINEs.pt | 640 | apache-2.0 |
| LibreDFINEm.pt | 640 | apache-2.0 |
| LibreDFINEl.pt | 640 | apache-2.0 |
| LibreDFINEx.pt | 640 | apache-2.0 |
| Instance segmentation | ||
| LibreDFINEn-seg.pt | 640 | apache-2.0 |
| LibreDFINEs-seg.pt | 640 | apache-2.0 |
| LibreDFINEm-seg.pt | 640 | apache-2.0 |
| LibreDFINEl-seg.pt | 640 | apache-2.0 |
| LibreDFINEx-seg.pt | 640 | apache-2.0 |
Tous les fichiers ci-dessus sont actuellement disponibles dans l<link>organisation LibreYOLO</link> et sont téléchargés à la première utilisation.
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
- D-FINE, University of Science and Technology of China
- Licence du projet d'origine
- Apache-2.0
- Source du projet d'origine
- github.com/Peterande/D-FINE
- Code de LibreYOLO
- MIT
- Poids
- Apache-2.0, republiés sur huggingface.co/LibreYOLO
- Interprétation
- Apache-2.0 is a permissive license, so these weights can be used in commercial and closed-source products. It asks you to keep its license text and attribution notices with any copy of the weights you redistribute, and it grants a patent license. It places no obligation on your own application code, and weights you train yourself on your own data are yours. The segmentation weights carry a second Apache-2.0 upstream, ArgoHA/D-FINE-seg, under the same terms.
Les poids de segmentation ont une seconde source amont : leur décodeur de masques, leur appariement de masques et leur loss de masques viennent de ArgoHA/D-FINE-seg, également en Apache-2.0, dont le mainteneur a approuvé la réutilisation avec attribution.
Citation
@misc{peng2024dfine,
title={D-FINE: Redefine Regression Task in DETRs as Fine-grained Distribution Refinement},
author={Yansong Peng and Hebei Li and Peixi Wu and Yueyi Zhang and Xiaoyan Sun and Feng Wu},
year={2024},
eprint={2410.13842},
archivePrefix={arXiv},
primaryClass={cs.CV}
}Copié depuis le bloc de citation des auteurs sur github.com/Peterande/D-FINE#citation.