D-FINE
ボックス回帰を各ボックス辺の確率分布として再定式化し、デコーダー層を通じて改良する検出Transformerです。LibreYOLOは物体検出とインスタンスセグメンテーションでD-FINEをサポートします。
- タスク
- detection, instance segmentation
- サイズ
- n, s, m, l, x at 640 px
- インストール
pip install libreyolo- サポートティア
- コア、v1.1.0以降。学習可能なコア検出器:機能は同じリリースサイクルでフラッグシップに続いて実装されます。
- ライセンス
- コード:Apache-2.0、重み:Apache-2.0。商用利用
インストール
D-FINEにオプションの追加パッケージは不要です。インポートするものはすべて基本インストールに含まれています。
pip install libreyololora=Trueによるアダプターのファインチューニングは例外で、lora追加パッケージが必要です。
pip install "libreyolo[lora]"推論
重みは初回使用時にHugging Faceからダウンロードされ、ローカルにキャッシュされます。
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 # ファイル名の -seg サフィックスでマスクヘッドを選択するため task# 引数は不要model = LibreYOLO("LibreDFINEn-seg.pt")result = model(SAMPLE_IMAGE, save=True) print(result.masks.data.shape)返されるResultsオブジェクトはすべてのファミリーに共通するため、別の検出器への切り替えは1行の変更で済みます。ファイル名に-segがあるとセグメンテーションタスクとして自動的に解決され、result.masksにはボックスとともにインスタンスマスクが格納されます。confとmax_detはクエリ選択をフィルタリングします。デコーダーはNMSステップを持たない集合予測器なので、iouはAPIの互換性のため受け付けられますが効果はありません。ソース、ストリーミング、結果の処理については推論を参照してください。
バリアント
5つのサイズがあります。すべて同じ入力解像度で動作するため、表ではパラメータ数と精度で区別しています。
| チェックポイント | 入力(px) | mAP 50-95 | パラメータ(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。LibreYOLOベンチマークハーネスで測定し、Vision Analysisで公開しています。そこではハードウェアおよびランタイム別のレイテンシを比較でき、完全な実行記録も確認できます。
セグメンテーションは検出のバックボーン、エンコーダー、デコーダーを再利用し、マスクヘッドを追加します。そのため、-segチェックポイントは対応する検出チェックポイントと同じ引数を受け取ります。LibreYOLOのRT-DETRv4ファミリーはD-FINEラッパーのサブクラスとして実装されています。このデコーダー系統を継承したうえで、マスクヘッドを持たないためタスクリストを検出のみに固定し直します。
学習
どちらのタスクも公開済みチェックポイントから学習を開始します。
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# 公開済みセグメンテーション重みから継続しマスクヘッドも含むlibreyolo train model=LibreDFINEn-seg.pt data=my-dataset.yaml \ task=segment epochs=50 imgsz=640# 検出重みにマスクヘッドはないため明示的な転移を実行# ヘッドは未学習で始まり学習後にのみ有用になる# ここで task=segment を指定すると転移を許可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=16設定を変更しなければ、トレーナーはlr0=2e-4、amp=Trueとamp_dtype="float16"、バッチサイズ16で132エポック実行し、改善がない状態が50エポック続くと早期終了します。libreyolo trainは、両タスクで同じ手順から始まります。AdamWとフラットなコサインスケジュール、weight_decay=1e-4、ウォームアップ2エポック、勾配ノルムのクリップ0.1で、モザイク、MixUp、HSV、アフィンの各データ拡張は使いません。name=を指定しない場合、実行結果はruns/train/dfine_expに保存されます。検出重みはセグメンテーション学習の有効な開始点ですが、明示的な転移としてのみ使用できます。マスクヘッドは未学習で始まり、そのままでは意味のないマスクを返すためです。CLIにtask=segmentを渡すことで転移を許可します。Python経由の手順にはさらに制限があります。LibreYOLO()ファクトリーは該当する引数を受け取らないため、allow_detect_to_segment_transfer=Trueを指定してLibreDFINEを直接構築する必要があります。また、直接構築ではダウンロードされないため、重みファイルがすでにディスク上になければなりません。
lora=Trueは検出に適用されます。セグメンテーション学習では拒否され、代わりにfreeze='backbone'を案内します。マスクヘッドがアダプターでテストされていないためです。Apple siliconでは、トレーナーが実行全体をCPUに移します。Integralのビン分割行列乗算の逆伝播でMetalのコンパイルエラーが発生するためです。MPSでの推論には影響しません。
データセット、データ拡張、マルチGPU、ロガーについては学習を参照してください。
検証
val()はメトリクス名をキーとする辞書を返し、verboseを有効のままにするとクラス別の結果を表示します。
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)"]) # マスクprint(metrics["metrics/mAP50-95(B)"]) # ボックス-segチェックポイントを対象にすると、通常のmetrics/mAP50-95キーにはマスクのスコアが格納されます。同じ実行で(B)のボックスと(M)のマスクも報告されるため、1回の処理で両方を取得できます。
エクスポート
| タスク | ONNX | TorchScript | ExecuTorch | TensorRT | OpenVINO | Paddle | MNN | RKNN | ncnn | TFLite | CoreML | Core AI |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Detection | Detection to ONNX:対応 | Detection to TorchScript:対応 | Detection to ExecuTorch:非対応 | Detection to TensorRT:対応 | Detection to OpenVINO:対応 | Detection to Paddle:対応 | Detection to MNN:対応 | Detection to RKNN:非対応 | Detection to ncnn:非対応 | Detection to TFLite:非対応 | Detection to CoreML:非対応 | Detection to Core AI:対応 |
| Instance segmentation | Instance segmentation to ONNX:対応 | Instance segmentation to TorchScript:対応 | Instance segmentation to ExecuTorch:非対応 | Instance segmentation to TensorRT:対応 | Instance segmentation to OpenVINO:対応 | Instance segmentation to Paddle:非対応 | Instance segmentation to MNN:非対応 | Instance segmentation to RKNN:非対応 | Instance segmentation to ncnn:非対応 | Instance segmentation to TFLite:非対応 | Instance segmentation to CoreML:非対応 | Instance segmentation to Core AI:非対応 |
エクスポートした成果物は、ファイルサフィックスに基づいてLibreYOLO()から再度読み込めます。そのため、.onnxまたは.engineファイルはチェックポイントと同様に動作し、同じResultsを返します。OpenVINO、Paddle、MNN、Core AIへのエクスポートでは、動的形状ではなく固定キャンバスを使用します。各形式が受け付ける引数と、一部の形式に追加される引数についてはエクスポートを参照してください。
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 # ファクトリーはファイルサフィックスで振り分けるためエクスポート成果物も# 任意のチェックポイントと同様に読み込まれ同じ Results オブジェクトを返すmodel = LibreYOLO("LibreDFINEn.onnx")result = model(SAMPLE_IMAGE) print(result.boxes.xyxy)ONNX の入力と出力
| テンソル | images float32 [batch, 3, height, width] |
|---|---|
| 色 | RGB |
| スケーリング | ピクセル値 / 255 |
| 正規化 | なし |
| リサイズ | 幅 x 高さに引き伸ばす(パディングなし、アスペクト比は保持しない), Pillow bilinear |
Pillow のバイリニアリサイズを再現する方法
LibreYOLO は Pillow の BILINEAR フィルタ(Image.resize)でリサイズします。これは OpenCV の INTER_LINEAR や INTER_AREA ではありません。縮小時、Pillow は縮小率の分だけフィルタを広げます。OpenCV のリサイズでは検出結果が変わり、ボックスが数ピクセルずれます。Pillow なしで再現するには、片方の軸をリサイズして 8 ビットに丸め、もう片方の軸をリサイズして再び丸めます。軸ごとに s = in_size / out_size、f = max(s, 1) とします。出力ピクセル i の中心は c = (i + 0.5) * s で、元画像のピクセル j を int(c - f + 0.5) から int(c + f + 0.5) - 1 まで(画像内に制限して)読み取り、それぞれの重みは max(0, 1 - |j + 0.5 - c| / f) で、重みの合計で割ります。Pillow は固定小数点で計算し、画像の形状から軸の順序を選ぶため、浮動小数点の重みでは一部のピクセルで 1 レベル異なることがあります。これは私たちの検証の結果を変えません。
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、デフォルトのエクスポート
| 出力 | 形状 | 意味 |
|---|---|---|
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. |
後処理
- 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、デフォルトのエクスポート
| 出力 | 形状 | 意味 |
|---|---|---|
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. |
後処理
- 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.
自分の実装を確認するには、同じファイルを LibreYOLO で実行します。LibreYOLO("model.onnx").predict("image.jpg") が基準となる結果を返します。 LibreYOLO 1.7.0 で検証済み。
チェックポイント
このファミリーで公開されているすべての重みファイルです。
| ファイル | 入力(px) | 重みのライセンス |
|---|---|---|
| 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 |
上記のすべてのファイルは現在LibreYOLO orgにあり、初回使用時にダウンロードされます。
ライセンス
ダウンロードする特定の重みについて、Hugging Faceリポジトリのライセンスを確認してください。LibreYOLO orgの各チェックポイントにはライセンスが付与されており、同じファミリー内でも常に同一とは限りません。そのリポジトリが正式な情報源です。以下の概要は、このページを最後に検証した時点で適用されていた内容を示します。
これは関連するライセンスの説明であり、法的助言ではありません。商用上重要な場合は、自分でライセンスを読み、専門家の助言を受けてください。
- 原著作物
- D-FINE, University of Science and Technology of China
- アップストリームのライセンス
- Apache-2.0
- アップストリームのソース
- github.com/Peterande/D-FINE
- LibreYOLOのコード
- MIT
- 重み
- Apache-2.0、huggingface.co/LibreYOLOで再公開
- 解釈
- 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.
セグメンテーション重みには2つ目のアップストリームがあります。マスクデコーダー、マスクマッチング、マスク損失は、同じくApache-2.0のArgoHA/D-FINE-segに由来し、そのメンテナーは帰属表示を伴う再利用を承認しています。
引用
@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}
}著者によるgithub.com/Peterande/D-FINE#citationの引用ブロックからコピーしています。