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.
pip install libreyoloO fine-tuning com adaptadores via lora=True é a exceção, e precisa do extra
lora.
pip install "libreyolo[lora]"Predição
Os pesos são baixados do Hugging Face no primeiro uso e ficam em cache localmente.
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 # 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.
| Checkpoint | Entrada (px) | mAP 50-95 | Parâmetros (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. 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.
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# 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# 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=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=16Por 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.
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)"]) # máscarasprint(metrics["metrics/mAP50-95(B)"]) # caixasContra 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
| Tarefa | ONNX | TorchScript | ExecuTorch | TensorRT | OpenVINO | Paddle | MNN | RKNN | ncnn | TFLite | CoreML | Core AI |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Detection | Detection to ONNX: compatível | Detection to TorchScript: compatível | Detection to ExecuTorch: incompatível | Detection to TensorRT: compatível | Detection to OpenVINO: compatível | Detection to Paddle: compatível | Detection to MNN: compatível | Detection to RKNN: incompatível | Detection to ncnn: incompatível | Detection to TFLite: incompatível | Detection to CoreML: incompatível | Detection to Core AI: compatível |
| Instance segmentation | Instance segmentation to ONNX: compatível | Instance segmentation to TorchScript: compatível | Instance segmentation to ExecuTorch: incompatível | Instance segmentation to TensorRT: compatível | Instance segmentation to OpenVINO: compatível | Instance segmentation to Paddle: incompatível | Instance segmentation to MNN: incompatível | Instance segmentation to RKNN: incompatível | Instance segmentation to ncnn: incompatível | Instance segmentation to TFLite: incompatível | Instance segmentation to CoreML: incompatível | Instance 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.
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 # 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
| Tensor | images float32 [batch, 3, height, width] |
|---|---|
| Cor | RGB |
| Escala | pixel / 255 |
| Normalização | nenhuma |
| Redimensionamento | esticar 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ída | Forma | Significado |
|---|---|---|
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
- 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, exportação padrão
| Saída | Forma | Significado |
|---|---|---|
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
- 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.
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.
| Arquivo | Entrada (px) | Licença dos pesos |
|---|---|---|
| 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 |
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.