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.
Origine
D-FINE par University of Science and Technology of China, Apache-2.0. Article, source
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.

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("LibreDFINEn.pt")result = model(SAMPLE_IMAGE, save=True) for box in result.boxes:    print(box.cls, box.conf, box.xyxy)
CLI
libreyolo predict model=LibreDFINEn.pt source=https://raw.githubusercontent.com/LibreYOLO/libreyolo/release/libreyolo/assets/parkour.jpg save=True
Segmentation d'instances
from 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.

CheckpointEntrée (px)mAP 50-95Paramètres (M)
LibreDFINEl64060.031.24
LibreDFINEm64057.819.59
LibreDFINEn64045.83.78
LibreDFINEs64053.410.32
LibreDFINEx64061.462.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.

Python
from libreyolo import LibreYOLO model = LibreYOLO("LibreDFINEn.pt")model.train(data="my-dataset.yaml", epochs=50, imgsz=640, batch=8, lr0=2e-4)
CLI
libreyolo train model=LibreDFINEn.pt data=my-dataset.yaml \  epochs=50 imgsz=640 batch=8 lr0=2e-4
Segmentation d'instances
# 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
Segmentation à partir de poids de détection
# 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=640
LoRA
from libreyolo import LibreYOLO model = LibreYOLO("LibreDFINEn.pt")model.train(data="my-dataset.yaml", epochs=50, lora=True)
Multi-GPU
libreyolo train model=LibreDFINEn.pt data=my-dataset.yaml \  epochs=50 device=0,1 batch=16

Laissé à 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.

Python
from libreyolo import LibreYOLO model = LibreYOLO("LibreDFINEn.pt")metrics = model.val(data="my-dataset.yaml") print(metrics["metrics/mAP50-95"])print(metrics["metrics/mAP50"])
CLI
libreyolo val model=LibreDFINEn.pt data=my-dataset.yaml
Segmentation d'instances
from 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îtes

Sur 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âcheONNXTorchScriptExecuTorchTensorRTOpenVINOPaddleMNNRKNNncnnTFLiteCoreMLCore AI
DetectionDetection to ONNX : pris en chargeDetection to TorchScript : pris en chargeDetection to ExecuTorch : non 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
Instance segmentationInstance segmentation to ONNX : pris en chargeInstance segmentation to TorchScript : pris en chargeInstance segmentation to ExecuTorch : non pris en chargeInstance segmentation to TensorRT : pris en chargeInstance segmentation to OpenVINO : pris en chargeInstance segmentation to Paddle : non 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. 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.

Python
from libreyolo import LibreYOLO model = LibreYOLO("LibreDFINEn.pt")model.export(format="onnx", imgsz=640)model.export(format="tensorrt", imgsz=640, half=True)
CLI
libreyolo export model=LibreDFINEn.pt format=onnx imgsz=640libreyolo export model=LibreDFINEn.pt format=tensorrt imgsz=640 half=True
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 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

Tenseurimages float32 [batch, 3, height, width]
CouleurRGB
Mise à l'échellepixel / 255
Normalisationaucune
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
SortieFormeSignification
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

  1. Apply sigmoid to pred_logits.
  2. 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.
  3. Keep the pairs whose score is above the confidence threshold (0.25 by default).
  4. 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.
  5. 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.
  6. LibreYOLO does not clip these boxes, so an edge can sit slightly outside the image.
Instance segmentation, export par défaut
SortieFormeSignification
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

  1. Apply sigmoid to pred_logits.
  2. 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.
  3. Keep the pairs whose score is above the confidence threshold (0.25 by default).
  4. 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.
  5. 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.
  6. A pixel belongs to the mask when its value is 0.5 or more.
  7. Clear every mask pixel outside the box. Pixel (x, y) stays only when x1 <= x < x2 and y1 <= y < y2, in original-image pixels.
  8. 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.
  9. 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.

FichierEntrée (px)Licence des poids
Detection
LibreDFINEn.pt640apache-2.0
LibreDFINEs.pt640apache-2.0
LibreDFINEm.pt640apache-2.0
LibreDFINEl.pt640apache-2.0
LibreDFINEx.pt640apache-2.0
Instance segmentation
LibreDFINEn-seg.pt640apache-2.0
LibreDFINEs-seg.pt640apache-2.0
LibreDFINEm-seg.pt640apache-2.0
LibreDFINEl-seg.pt640apache-2.0
LibreDFINEx-seg.pt640apache-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.

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.