D-FINE

Um transformer de detecção que reformula a regressão de caixas como uma distribuição de probabilidade sobre cada borda da caixa, refinada ao longo das camadas do decoder. O LibreYOLO o suporta para detecção e segmentação de instâncias.

Tarefas
detection, instance segmentation
Tamanhos
n, s, m, l, x at 640 px
Instalação
pip install libreyolo
Nível de suporte
Núcleo, desde a v1.1.0. Detectores treináveis do núcleo: os recursos chegam depois dos carros-chefe na mesma leva de versões.
Origem
D-FINE por University of Science and Technology of China, Apache-2.0. Artigo, código-fonte
Licenças
Código Apache-2.0, pesos Apache-2.0. Uso comercial

Instalação

O D-FINE não precisa de nenhum extra opcional. Tudo que ele importa já está na instalação base.

bash
pip install libreyolo

O fine-tuning com adaptadores via lora=True é a exceção, e precisa do extra lora.

bash
pip install "libreyolo[lora]"

Predição

Os pesos são baixados do Hugging Face no primeiro uso e ficam em cache localmente.

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
Segmentação de instâncias
from libreyolo import LibreYOLO, SAMPLE_IMAGE # O sufixo -seg no nome do arquivo seleciona a cabeça de máscaras, então# nenhum argumento task é necessário aqui.model = LibreYOLO("LibreDFINEn-seg.pt")result = model(SAMPLE_IMAGE, save=True) print(result.masks.data.shape)

O objeto Results retornado é o mesmo que todas as famílias retornam, então trocar por outro detector é uma mudança de uma linha. Um nome de arquivo com -seg já resolve sozinho para a tarefa de segmentação, e aí result.masks carrega as máscaras de instância junto com as caixas. conf e max_det filtram a seleção de queries; iou é aceito por paridade de API mas não tem efeito, porque o decoder é um preditor de conjuntos sem etapa de NMS. Veja predição para fontes, streaming e tratamento de resultados.

Variantes

Cinco tamanhos. Todos rodam na mesma resolução de entrada, então a tabela os separa por número de parâmetros e acurácia.

CheckpointEntrada (px)mAP 50-95Parâmetros (M)
LibreDFINEl64060.031.24
LibreDFINEm64057.819.59
LibreDFINEn64045.83.78
LibreDFINEs64053.410.32
LibreDFINEx64061.462.62

COCO val2017, 500 images. Medido pelo conjunto de testes de benchmark do LibreYOLO e publicado no Vision Analysis, onde a latência entre hardwares e runtimes é comparada e os registros completos das execuções ficam disponíveis.

A segmentação reaproveita o backbone, o encoder e o decoder da detecção e acrescenta uma cabeça de máscaras, então um checkpoint -seg aceita os mesmos argumentos que o irmão de detecção. A família RT-DETRv4 do LibreYOLO é escrita como uma subclasse do wrapper do D-FINE: ela herda essa linhagem de decoder e depois fixa sua lista de tarefas de volta em detecção, porque não traz cabeça de máscaras.

Treinamento

O treinamento parte de um checkpoint publicado, para as duas tarefas.

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
Segmentação de instâncias
# Continua a partir de pesos de segmentação publicados, cabeça de máscaras incluída.libreyolo train model=LibreDFINEn-seg.pt data=my-dataset.yaml \  task=segment epochs=50 imgsz=640
Segmentação a partir de pesos de detecção
# Os pesos de detecção não trazem cabeça de máscaras, então isto é uma# transferência explícita: a cabeça começa sem treinamento e só serve depois# de treinada. Pedir task=segment aqui é o que autoriza a transferência.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

Por padrão, o trainer roda 132 épocas com lr0=2e-4, amp=True e amp_dtype="float16", batch de 16 e early stopping após 50 épocas sem melhora. O libreyolo train parte da mesma receita para as duas tarefas: AdamW com um schedule de cosseno plano, weight_decay=1e-4, 2 épocas de warmup, um clip de norma do gradiente de 0.1, e sem augmentation de mosaic, MixUp, HSV ou afim. Sem name=, suas execuções vão para runs/train/dfine_exp. Pesos de detecção são um ponto de partida válido para treinamento de segmentação, mas só como transferência explícita, pois a cabeça de máscaras começa sem treinamento e, de outro modo, retornaria máscaras sem sentido. Passar task=segment na CLI autoriza a transferência. Em Python, o caminho é mais restrito: é preciso construir LibreDFINE diretamente com allow_detect_to_segment_transfer=True, porque a factory LibreYOLO() não aceita esse argumento, e a construção direta não faz download, então o arquivo de pesos já deve estar no disco.

lora=True vale para detecção. O treinamento de segmentação o rejeita e aponta para freeze='backbone' no lugar, porque a cabeça de máscaras não foi testada com adaptadores. No Apple silicon o trainer move a execução inteira para a CPU: o backward pass do matmul por bins do Integral esbarra em uma falha de compilação do Metal. A inferência em MPS não é afetada.

Veja treinamento para datasets, data augmentation, multi-GPU e loggers.

Validação

val() retorna um dicionário indexado pelo nome da métrica, e imprime os resultados por classe quando verbose fica ligado.

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
Segmentação de instâncias
from libreyolo import LibreYOLO model = LibreYOLO("LibreDFINEn-seg.pt")metrics = model.val(data="my-dataset.yaml") print(metrics["metrics/mAP50-95(M)"])   # máscarasprint(metrics["metrics/mAP50-95(B)"])   # caixas

Contra um checkpoint -seg, a chave metrics/mAP50-95 pura contém a pontuação das máscaras, e a mesma execução também reporta as caixas em (B) e as máscaras em (M), então as duas ficam disponíveis em uma única passada.

Exportação

TarefaONNXTorchScriptExecuTorchTensorRTOpenVINOPaddleMNNRKNNncnnTFLiteCoreMLCore AI
DetectionDetection to ONNX: compatívelDetection to TorchScript: compatívelDetection to ExecuTorch: incompatívelDetection to TensorRT: compatívelDetection to OpenVINO: compatívelDetection to Paddle: compatívelDetection to MNN: compatívelDetection to RKNN: incompatívelDetection to ncnn: incompatívelDetection to TFLite: incompatívelDetection to CoreML: incompatívelDetection to Core AI: compatível
Instance segmentationInstance segmentation to ONNX: compatívelInstance segmentation to TorchScript: compatívelInstance segmentation to ExecuTorch: incompatívelInstance segmentation to TensorRT: compatívelInstance segmentation to OpenVINO: compatívelInstance segmentation to Paddle: incompatívelInstance segmentation to MNN: incompatívelInstance segmentation to RKNN: incompatívelInstance segmentation to ncnn: incompatívelInstance segmentation to TFLite: incompatívelInstance segmentation to CoreML: incompatívelInstance segmentation to Core AI: incompatível

Um artefato exportado é recarregado pelo LibreYOLO() a partir do sufixo do arquivo, então um arquivo .onnx ou .engine se comporta como um checkpoint e devolve o mesmo Results. Os caminhos de OpenVINO, Paddle, MNN e Core AI exportam com um canvas fixo em vez de formas dinâmicas. Exportação lista os argumentos que todo formato aceita e os extras que alguns deles acrescentam.

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
Usar o arquivo exportado
from libreyolo import LibreYOLO, SAMPLE_IMAGE # A factory decide pelo sufixo do arquivo, então um artefato exportado# carrega como qualquer checkpoint e devolve o mesmo objeto Results.model = LibreYOLO("LibreDFINEn.onnx")result = model(SAMPLE_IMAGE) print(result.boxes.xyxy)

Entradas e saídas ONNX

Tensorimages float32 [batch, 3, height, width]
CorRGB
Escalapixel / 255
Normalizaçãonenhuma
Redimensionamentoesticar para largura x altura (sem preenchimento, a proporção não é mantida), Pillow bilinear
Como reproduzir o redimensionamento bilinear do Pillow

O LibreYOLO redimensiona com o filtro BILINEAR do Pillow (Image.resize). Não é OpenCV INTER_LINEAR nem INTER_AREA: ao reduzir, o Pillow alarga o filtro pelo fator de redução, e os redimensionamentos do OpenCV mudam as detecções e deslocam as caixas em vários pixels. Para reproduzi-lo sem o Pillow, redimensione um eixo, arredonde para 8 bits, depois redimensione o outro eixo e arredonde de novo. Por eixo, seja s = in_size / out_size e f = max(s, 1). O pixel de saída i tem centro c = (i + 0.5) * s e lê os pixels de origem j de int(c - f + 0.5) até int(c + f + 0.5) - 1, limitados à imagem, cada um com peso max(0, 1 - |j + 0.5 - c| / f), dividido pela soma dos pesos. O Pillow calcula em ponto fixo e escolhe a ordem dos eixos pela forma da imagem, então pesos em ponto flutuante podem diferir em um nível em alguns pixels. Isso não muda os resultados nas nossas verificações.

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, exportação padrão
SaídaFormaSignificado
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.

Pós-processamento

  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, exportação padrão
SaídaFormaSignificado
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.

Pós-processamento

  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.

Para conferir a sua própria implementação, passe o mesmo arquivo pelo LibreYOLO: LibreYOLO("model.onnx").predict("image.jpg") devolve os resultados de referência. Verificado com o LibreYOLO 1.7.0.

Checkpoints

Todos os arquivos de pesos publicados desta família.

ArquivoEntrada (px)Licença dos pesos
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

Todos os arquivos acima existem hoje na organização LibreYOLO e são baixados no primeiro uso.

Licenciamento

Confira a licença no repositório do Hugging Face correspondente aos pesos que você baixar. Cada checkpoint na organização LibreYOLO tem uma licença, e ela nem sempre é a mesma em toda a família. Esse repositório é a fonte oficial. O resumo abaixo descreve o que se aplicava na última verificação desta página.

Esta é uma descrição das licenças envolvidas, não uma orientação jurídica. Se a resposta tiver importância comercial, leia as licenças e procure sua própria assessoria.

Trabalho original
D-FINE, University of Science and Technology of China
Licença original
Apache-2.0
Código-fonte original
github.com/Peterande/D-FINE
Código do LibreYOLO
MIT
Pesos
Apache-2.0, republicado em huggingface.co/LibreYOLO
Interpretação
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.

Os pesos de segmentação têm um segundo upstream: o decoder de máscaras, o matching de máscaras e a loss de máscaras vêm do ArgoHA/D-FINE-seg, também Apache-2.0, cujo maintainer aprovou o reuso com atribuição.

Citação

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

Copiado do bloco de citação dos autores em github.com/Peterande/D-FINE#citation.

Verificado com o LibreYOLO v1.6.0. As tabelas de suporte, os checkpoints e os números de benchmark desta página são gerados a partir da biblioteca lançada e dos pesos publicados, não escritos à mão.