Releases: PogChamper/dfine-cpp
Release list
v0.5.0 — Your checkpoint, your dataset, proven
v0.5.0 — Your checkpoint, your dataset, proven
The most requested capability since v0.4.0: taking this pipeline to a model that is not COCO.
This release makes that a first-class, verifiable path — export a fine-tuned D-FINE checkpoint
without a training checkout, evaluate it on your own COCO-format dataset, and compare operating
points through a chain that refuses to compare the wrong things. The published model artifacts
are byte-identical to v0.3.1–v0.4.0; no re-export is required.
Validate on your own dataset
preset_sweep(dfine sweep) runs the whole comparison in one command: export,slim
conversion, engine builds, accuracy on your split, baseline deltas, and native throughput over
configurable operating points (graph × precision × engine profile × runtime mode), assembled
into one decision table with an--ap-budgetrecommendation. Every step is the documented tool
run with its argv recorded, so the table is reproducible by hand.- D-FINE-seg YOLO splits convert on the fly (
--yolo-dataset);yolo_to_coco.pyis the
standalone converter. - Validation is a reproducible workflow for a custom checkpoint and any
COCO-format detection dataset: any class count, the same 640×640 stretch contract, standard
COCO bbox metrics. - Accuracy reports carry AP/AR slices, per-IoU and per-class metrics, GT density, and
original-pixel versus model-space object-size breakdowns, plus annotation, image, evaluator,
artifact, and lineage hashes. accuracy_chain.pyassembles export → TensorRT → precision → preset deltas and rejects reports
with different annotations, image bytes, preprocessing, thresholds, Top-K, inference batch,
evaluator source, GT population, model contract, or artifact lineage. Reports that predate
lineage recording are rejected unless--allow-missing-lineageis passed.- The v0.5 preset report is the worked example: four
independently fine-tuned cross-domain datasets (RF4) plus full COCO, five graph presets, every
backend transition isolated.
Self-contained checkpoint export
- The detection-only D-FINE definition is bundled; export no longer needs a training repository
checkout. Breaking: export requires an explicit--checkpoint;--dfine-srcand
DFINE_SEG_DIR/DFINE_SEG_SRCare removed from the export toolchain. - A path-gated CI job proves the bundled model bit-exact against the pinned D-FINE-seg revision
over all five published checkpoints whenever the bundle or the pin changes. - Checkpoint provenance is strict, model packs are validated canonically, and engine builders
deserialize the published plan to verify its compiled batch profile before recording metadata.
Benchmark surface
- The throughput surface was re-measured under an idle-gated protocol: five interleaved
single-round processes per configuration, published medians with min–max ranges. Batch-8 gains
are monotonic in pruned query count;Q200→C100is the fastest preset at +9.7%. - Runtime modes are now published points: full-pipeline CUDA Graph and 1/8/8 serving profiles,
including themaxconfiguration — 1.99 ms at batch 1 under graph capture and 662 img/s at
batch 8 (−0.96 COCO AP), measured with the standard fidelity chain. - A controlled eager versus
torch.compilebaseline accompanies the study.
Runtime and tooling contracts
- GPU-decode host staging buffers are pinned, so the mode's async copies stay asynchronous and
the reported dispatch/wait timing split is truthful; detections are unchanged. profile.pyenforces--topkon the native accuracy backend and rejects values above the
native decode limit.- Evaluation reports are stretch-only end to end; the producer-less letterbox report schema was
removed andaccuracy_chainrejects letterbox geometry.
Assets
The wheel is dfine-0.5.0-py3-none-linux_x86_64.whl; the model pack republishes the pinned
v0.3.1-lineage artifacts unchanged. Install and verification commands are in
Getting started; the asset grammar is in Naming.
v0.4.0 — Build correctly. Run natively. Prove it.
v0.4.0 — Build correctly. Run natively. Prove it.
This release moves the project's guarantees from the maintainer's knowledge into executable
contracts: the code validates its assumptions, sidecars record provenance, tooling fails on
incomplete data, and the documentation states the runtime's actual behavior. The published
model artifacts are byte-identical to v0.3.1–v0.3.3; no re-export is required.
Behavior tightened at several boundaries — see the runtime and validation sections for the
rejections that were previously silent.
Runtime contract
- Detector destruction drains pending CUDA work before releasing detector-owned buffers.
- Engine loading validates the D-FINE IO layout, tensor types, and single-profile batch contract.
- Batch limits come from the TensorRT optimization profile and are cross-checked against engine
sidecars. - Explicit metadata paths are strict; automatic discovery still supports appended and same-stem sidecars.
- ONNX and engine sidecars are distinguished so an ONNX build recommendation is not mistaken for
the engine's actual optimization profile. - Legacy untagged sidecars remain supported; only metadata with engine build facts asserts profile
fields. - Engines may expose additional outputs when logits and boxes are identified by canonical or
sidecar names; shape-only discovery remains limited to exactly two outputs. - Model input remains RGB.
ImageU8::is_bgrdescribes source pixels; a sidecar that declares BGR
model input is rejected rather than silently ignored. - Decode uses a fixed
min(300, Q×C)candidate limit; sidecars do not override it. - Full-val mAP is retained across the five
slimengines and two reduced-query checks; TensorRT
inference time is unchanged. FreezeSpecrejects incomplete or negative source dimensions and applies explicit width and height
bounds independently.- A rejected enqueue or deferred CUDA execution failure makes the detector unusable; recreate it
before retrying inference. cuda_graph_replays()reports calls served by the enqueue/output-copy graph path.- C++ and Python constructor thresholds must be finite and within
[0, 1]. A finite negative C++
per-call value retains the default-threshold sentinel; Python usesNoneand validates explicit
per-call values against[0, 1]. - C ABI constructor thresholds reject non-finite values and positive values above 1; finite values
at or below 0 retain the 0.5 default. - Explicit letterbox padding must be within
[0, 255]; negative C ABI values retain the default
value of 114.
Build and packaging
- Installed CMake consumers no longer require CUDA or TensorRT development packages in
dfineConfig.cmake. - The C++ FP32 builder disables TF32;
--cuda-graphsets zero auxiliary streams, and both facts
are recorded in its engine sidecar. - The Python builder records graph compatibility only for FP32-output, zero-aux-stream engines.
dfine build --cuda-graphselects the stream policy; cached builds use a distinct-g0entry. - Wheel, graph, and engine publication is atomic: path collisions are rejected and a failed build
preserves the previous artifact pair. The wheel is a nativepy3-none-linux_x86_64distribution
with LICENSE and NOTICE included. - New checkpoint exports record the D-FINE source repository, revision, and dirty state, plus the
exporter hash and ONNX simplification result. - Surgical FP16 sidecars identify the source graph, converter, and tool version; research-only
precision overrides are marked experimental rather than labeled as the release recipe. - Export fails before model setup when the validated D-FINE source revision is missing or malformed.
- Release assembly validates the model contract, ONNX structure, FP32-to-slim lineage, wheel
contents, checkpoint and tool provenance, version, and complete asset set before staging upload
bytes.
Validation
- Evaluation aborts on missing, empty, or partial datasets and on zero detections.
- Benchmark and report tooling rejects invalid measurement counts and failed TensorRT API calls.
Full-graph validation requires an active graph and one replay per measured call.
v0.3.3 — the clean-machine release
v0.3.3 — the clean-machine release
Everything in this release exists because two rented GPU boxes were set up from
bare Ubuntu and every pothole got a fix at the layer it belongs to. Model files
are byte-identical to v0.3.1/v0.3.2 — no recipe changed, no re-export needed.
Validation now spans three GPU generations.
Validated: Ampere, Ada, Blackwell
Full-methodology benchmark runs (batches 1/2/4/8 × 500 iters, 3 interleaved
rounds, VRAM, subset-mAP lossless checks) on RTX 3090 and RTX 5080 join the Ada
reference — tables in docs/VALIDATION.md. The tier ladder and the lossless
surgical-FP16 claim reproduce on all three generations, and two findings are
worth knowing:
- the published wheel (sm_89) runs on RTX 50xx out of the box via PTX JIT —
verified on an RTX 5080 with detections identical to the README; - README batch-1 numbers carry a WSL2 dispatch tax: native Linux is faster in
the dispatch-bound regime (RTX 5080 holds n-surgical at 0.91 ms end to end).
Installation and build, hardened
./build.shpreflights before cmake: missing TensorRT headers now fail
with the three remedies (pinned apt chain / NGC container / no-root tarball)
instead of aCould NOT find TensorRTwall; a conda cross-g++ on PATH is
bypassed for the system toolchain; conda-injectedNVCC_PREPEND_FLAGS(fatal
after a double activation) is dropped; a pre-Turing GPU is refused with the
actual constraint named.- The pip
tensorrtmetapackage now resolves to CUDA-13 (10.13.3.9.post1):
every pin and instruction in this repo saystensorrt-cu12explicitly, and
this release's wheel bakes the corrected[tensorrt]extra — fresh
dfine[tensorrt]installs work again. dfine doctor: one command prints the environment facts every bug report
needs — GPU/driver/SM, the tensorrt import, every libdfine candidate path
with its verdict, header presence, the engine cache. Exit code answers "does
the library load here".- uv replaces conda in the scripts environment:
uv sync --frozen --extra gpu --extra torchprepares everything, and the committeduv.lockpins the
export toolchain — which is what byte-reproducible exports actually require
(the cross-machine DIFFERS verdicts traced to an unpinned torch). New exports
recordtool_versionsin the sidecar so a byte mismatch is diagnosable from
metadata alone. conda remains a documented no-root fallback. docs/TROUBLESHOOTING.md: the field notes, organized by symptom.
CI now dogfoods the documented install
All container jobs start from nvidia/cuda:12.9.1-devel and install TensorRT
10.13 through the same pinned apt chain the docs prescribe — so the install
path users follow is exercised on every commit, and the wheel is compiled
against the same TensorRT headers as the validated runtime (the 24.10 NGC
image compiled against 10.5, and every load printed a version-mismatch
warning).
Behavior notes
dfine doctoris a new subcommand; no existing command changed.- ONNX sidecars written by new exports gain
tool_versions; published assets
and existing caches are untouched. - The INT8 record in
docs/HANDOFF.mdcarries an addendum: the historical
mAP-0.13 collapse was this repo's naive PTQ path, not INT8 itself — an
external SmoothQuant recipe reaches −0.97 AP and still loses to surgical
FP16 on desktop Ada, so the desktop verdict stands.
v0.3.2 — names are labels, sidecars are truth; installable C++
v0.3.2 — names are labels, sidecars are truth; installable C++
An integration and insurance release: artifact identity moves from filenames
into metadata, the C++ library becomes properly installable, and the release
process itself is now mechanical. Model files are byte-identical to v0.3.1 —
no re-export needed, no precision recipe changed.
Behavior changes
- Engine resolution reads the sidecar, not the filename. The CLI picks a
cached engine's batch profile from its JSON sidecar (the filename regex
remains only as a fallback for pre-sidecar engines), and an engine whose
recordedonnx_sha256contradicts the resolved ONNX is refused with a
warning instead of served — a hand-copied or renamed engine can no longer
silently answer for the wrong model.docs/NAMING.mddocuments the whole
scheme (four identity axes; name grammar assembled in exactly one place). dfine_build(C++ builder) refuses non-FP32 graphs up front. Before, a
slim/fp16 ONNX went through a minutes-long build and came out stamped
precision: fp32next to the converter's contradictingprecision_mode.
Use the mAP-validated Python pipeline (build_engine.py) for fp16/int8.
Its default engine name also switches from<stem>-fp32.engineto
<stem>_fp32.engine— the underscore grammar every other tool discovers.dfine exportwarns before overwriting a cached slim/legacy export
(previously only the FP32 base got the different-checkpoint note).- Engine sidecars carry more build truth:
schema_version: 1,sm_arch,
tf32,max_aux_streamsjoin the existing fields, and publishing an engine
removes a stale appended-name sidecar twin that would otherwise shadow the
fresh one for every reader.
New: use dfine from your own CMake project
cmake --install now ships a complete config package: versioned .so chain,
public headers (TensorRT/CUDA-free — PIMPL), dfineConfig.cmake with
find_dependency resolution through the bundled FindTensorRT.cmake.
find_package(dfine CONFIG REQUIRED)
target_link_libraries(your_app PRIVATE dfine::dfine)examples/consumer/ is the documented out-of-tree consumer; a new CI job
installs to a prefix, audits relocatability (no RPATH, no build-machine
paths, SONAME libdfine.so.1), and builds the consumer outside the checkout
on every commit.
Diagnostics and contracts
- Loader:
DFINE_LIBRARYpointing at a missing file is now a hard error
(an explicitly requested library is never silently substituted), and when
nothing loads, the error lists both the searched paths and each dlopen's
own words — "not found" vs "found but missing a dependency" finally look
different. - Log callback:
c_api.hstates the real contract (any thread, message
valid only during the call, the swap does not drain in-flight invocations —
keep installed callbacks alive for the process lifetime). The Python wrapper
now follows it by keeping every installed trampoline alive.
Release and validation tooling
trt-files/scripts/release_assets.pyreplaces the hand-assembled
SHA256SUMS:assemblevalidates the 20-file release grammar (graph/sidecar
pairing, precision-vs-suffix, opset) and writes the manifest with the wheel
included;verify --tagdownloads a published release back and fails on any
mismatch or any published asset the manifest does not cover. Both modes are
how this release was produced and checked.trt-files/scripts/validation_report.py+docs/VALIDATION.md: anyone with
a different GPU/TensorRT can produce a comparable report (environment, asset
hashes, engine build, benchmark) and submit it as a validation-matrix row.
The Ada/WSL2 row ships with this release.
Housekeeping
SPDX license strings (PEP 639) and package auto-discovery silence both
setuptools deprecation warnings in the wheel build; the wheel-bundled
_scripts/ no longer trips packaging. One stale ruff ignore dropped.
v0.3.1 — no silently wrong results
v0.3.1 — no silently wrong results
A hardening release: every confirmed path where the library could keep running in an
inconsistent state, or produce the wrong model without saying so, is closed and covered
by tests. No new features. Behavior changes users should know about, in order of impact:
Behavior changes
dfine export --precision fp16now produces the v0.3 production tier (opset-19 base +
convert_fp16_surgical.py --slim, written asdfine_<size>_slim.onnx). Before v0.3.1 the CLI
silently produced the v0.2 decoder-FP32 tier (~11% below the README numbers at batch 8).
If you exported a custom model through the CLI, re-export it to pick up the production
recipe. The old tier remains available as--precision fp16-legacy(opset 16).- Checkpoint loading is strict by default. A checkpoint whose learned tensors do not
exactly fill the model (wrong--model-name, missing--num-classes) now stops the export
with the offending tensors and a hint, instead of exporting randomly initialized weights.
Size-derived geometry buffers (decoder.anchors/valid_mask) are the one exception: at the
training size the checkpoint's copies load as before (keeping exports byte-reproducible with
the gated v0.3.0 assets), and at a retargeted--img-sizethe freshly generated geometry is
used instead of failing. Research escape hatch:--allow-partial-checkpoint(recorded in the
sidecar).dfine exportgains--num-classes/--class-names. - CLI output contracts.
predict --jsonkeeps stdout pure JSON in every mode (all
diagnostics, including the--outconfirmation and engine-build chatter, go to stderr);
info/benchdrop their--onnxflag (it was parsed and never read). Engine cache entries
use a new content-fingerprinted naming scheme — old cache entries keep working as a warned
fallback; rebuild to bind them.
Runtime: errors are now safe
- TensorRT shape transitions are transactional. Two paths previously left the session
inconsistent behind a catchable exception: a frozen detector receiving a larger batch left the
TRT context reconfigured while the shape cache said otherwise (the next call silently ran
batch-2 shapes against batch-1 buffers — device OOB); an allocation failure mid-grow left the
context holding a freed buffer address. Now a failed transition either leaves the previous
state fully intact (frozen violations are rejected before the context is touched) or the
session refuses to run until repaired/recreated. Covered by fault-injection tests
(tests/test_shape_transitions.cpp) and a public-API recovery suite
(tests/test_detector_recovery.cpp); memcheck-clean under compute-sanitizer. - Image geometry is validated at every entry point (C++ and C ABI share one validator):
stride < width*channels— the pixels-vs-bytes mixup — was accepted by the C++ path and
produced sheared images plus an out-of-bounds read.
Artifacts: identity and honesty
- The engine cache is bound to artifact identity. The filename embeds a fingerprint of
the ONNX bytes + its sidecar; the batch profile stays in the name but is not identity — an
engine built with a serving profile is still found bypredict(largest max-batch wins,
numerically). An explicit--onnxcan never lose to a cache entry built from something
else — previously a stale COCO engine could silently serve a freshly exported custom model.
Provenance-less fallbacks warn and never win silently among several candidates. - Precision metadata is written by whoever set the compute types. Strongly-typed FP16
engines no longer get stamped"precision": "fp32"by the builder; the converter's
precision/precision_modepass through, and the builder appends its own facts
(network_typing,trt_version, batch profile,onnx_sha256). - Sidecar values are validated at load (zero/non-finite std, unknown resize mode, inverted
batch ranges, class-name/count mismatch, unsupported schema version), and a present sidecar
is cross-checked against the engine bindings — a stale file cannot mislabel detections. - Exports run a mandatory dynamic-batch postcondition (the graph is executed at N=1 and
N=2 via onnxruntime): a--trace-batch 1-style baked extent passes every static check and is
only caught by running — now it cannot leave the export step.--trace-batch < 2is rejected
outright; the exporter default opset is 19. - Interrupted writes are far harder to weaponize. Every artifact producer (exporter,
fp16/fp16-legacy/int8 converters, engine builder) stages BOTH the graph and its sidecar in
temp files before either goes live, then publishes them with two adjacent atomic renames;
a failed export gate deletes its staging, and a producer whose source carries no sidecar
REMOVES a stale output sidecar instead of leaving the previous graph's metadata next to
the new file. Covered by tests against every producer's publish path. Remaining caveat,
stated plainly: the pair is two renames, not one transaction — a crash exactly between the
two syscalls can still pair a new graph with old metadata for that instant.
Tooling and packaging
dfine predict --jsonkeeps stdout pure JSON (all diagnostics and build chatter go to
stderr) — pipes intojqeven on a cold cache.coco_eval.py/profile.pyno longer crash on 1-class models at the default--topk.- CI packages the wheel through
python/build_wheel.shitself (the v0.3.0 CI wheel silently
lacked the bundledbuild_engine.py), audits the payload, strips and forbids RPATH in the
bundledlibdfine.so(a baked build-machine path is searched beforeLD_LIBRARY_PATH),
and smoke-installs outside the checkout through the CLI's real script-resolution path. dfine info/dfine benchdrop their--onnxflag (it was parsed and never read).
Artifacts
- Five opset-19 FP32 graphs and five surgical/slim FP16 graphs, each with its JSON sidecar:
dfine_{n,s,m,l,x}_{op19,slim}.{onnx,json}. The ONNX bytes are identical to the gated
v0.3.0 assets; the regenerated sidecars add strict checkpoint provenance. dfine-0.3.1-py3-none-linux_x86_64.whl(CUDA sm_89/PTX wheel, TensorRT/CUDA supplied by
the target machine).SHA256SUMS, covering all 21 payload files above.
Docs and attribution
NOTICE/README now credit rf-detr-cpp (Apache-2.0) as the origin of the runtime scaffolding,
with per-file derivation notices; CONTRIBUTING/ROADMAP/README were swept for statements that
contradicted the shipped v0.3 recipes (decoder-FP32 rule, INT8 scoping, WASM promise);
HANDOFF is explicitly the historical journal. New: docs/RELEASE_CHECKLIST.md — the executable
release gate this release was verified against.
v0.3.0 — surgical FP16 + export sliders
D-FINE-cpp v0.3.0
Surgical FP16 and export-time speed sliders. The production ONNX moves from "FP16 with the decoder
kept FP32" to whole-net FP16 with a minimal FP32 island — lossless full-val mAP on all five
sizes at +6…19% batch-8 throughput — and the export script gains sliders that trade fractions of
an AP point for up to +46% over the v0.2.0 tier. No ABI change; v0.2.0 binaries and engines keep
working.
Surgical FP16 (convert_fp16_surgical.py, new production default)
The decoder is ~46% of GPU time and was FP32 until now — not because it all needs the precision,
but because naive decoder FP16 collapses mAP. The surgical converter runs the whole net FP16,
including the deformable-attention data path, and pins only what measurably needs FP32: the FDR
scopes (Integral/LQE/bbox heads) and the deform coordinate/index math (FP16 integers above 2048
are inexact — wrong-pixel gathers). --slim (the release default) is the tightest gated island.
- Lossless, full COCO val, all five sizes —
--slim: n 0.4272, s 0.5060, m 0.5500 (== the
fp16_st reference exactly), l 0.5723, x 0.5926; non-slim surgical: n 0.4276, s 0.5065,
m 0.5502, l 0.5724, x 0.5929. - Batch-8 (surgical tier, conservative — slim benched +2-3% on top where measured): n 1234→1309,
s 637→758, m 469→526 (561 with--opt-batch 8), l 357→390, x 244→264 img/s;
VRAM −28…−124 MiB; zero plugins. - Requires an opset-19 export and hard-errors below it: opset-16 exports decompose LayerNorm
and TensorRT 10.13 miscompiles the decomposition in FP16 (mAP → ~0.005 while ONNXRuntime stays
healthy; minimal repro archived, NVIDIA report in preparation). - The full-pipeline CUDA graph runs on a
--max-aux-streams 0surgical engine unchanged:
byte-identical detections, 2.474 ms end-to-end batch-1 — the repo's latency record.
Export sliders (export_dfine_onnx.py)
Three decoder reshapes applied before deploy()/tracing, so the graph itself shrinks
(m, full-val, b8, gains vs the surgical b8 median): --num-queries 200 = −0.13 AP / +7%;
--cascade K:KEEP = keep the top-KEEP queries after layer K ranked by that layer's trained
deep-supervision head (1:150 = −0.18 AP / +8%, the best single slider); --eval-idx 2 =
−0.57 AP / +4%. Composed presets: fast
(Q200 + cascade 1:100) = +11…19% over surgical across the lineup at −0.44…−0.77 AP; max (fast +
eval-idx 2 + --opt-batch 8) = 686 img/s on m, 10.4× PyTorch, −0.89 AP. Every measured point, including
the paths that closed negative (FP8, INT8, deform plugin), is in
docs/RESEARCH_MATRIX.md.
Python: engine builds without a repo checkout
The wheel now bundles a snapshot of build_engine.py (self-contained: tensorrt + stdlib), so the
release quickstart is wheel + two curls + one dfine build — verified end-to-end in a fresh venv.
dfine build gains --opt-batch; --onnx without --model now derives the cache name from the
ONNX stem instead of producing a dfine_None engine; fp16/fp32 ONNX resolution understands the
new _slim/_op19 release names. New notebook:
examples/python_quickstart.ipynb.
Validation
WERROR=ON build clean; C-ABI byte-parity PASS (fp32 + fp16_st); 14/14 pytests; the default
export path is byte-identical with the new flags unset (same-session A/B of the ONNX and
sidecar). The flag-based exports reproduce the research artifacts that passed the full-val gates
bit-exactly (graph node/initializer hashes match for the fast preset and for all five slim
release assets), so the shipped flags inherit those gates directly. Slider engines were
additionally gated: cascade 1:150 full-val 0.5482 (−0.18), fast preset full-val on all five sizes.
Artifacts
dfine_{n,s,m,l,x}_op19.onnx (FP32 opset-19 base) + dfine_{n,s,m,l,x}_slim.onnx (surgical-FP16
production) + .json sidecars + SHA256SUMS + dfine-0.3.0-py3-none-linux_x86_64.whl (sm_89;
needs local TensorRT 10.x + CUDA 12) + demo mp4s. The v0.2.0 fp16_st/fp32 op16 assets remain
valid and stay on the v0.2.0 release.
v0.2.0 — C ABI v2, full Python parity
D-FINE-cpp v0.2.0
C ABI v2 and full Python parity with the C++ feature set. Model artifacts are unchanged from
v0.1.0 and re-attached here so every release is self-contained.
C ABI v2 (breaking — one-time)
dfine_options_t gains a leading struct_size field and the intensive-core/preprocessing
options. This is the last planned ABI break: the size-versioning contract (the library reads
at most struct_size bytes; new fields are only ever appended) makes all future growth
backward-compatible. Binaries built against the pre-0.2.0 header must be rebuilt; a zero
struct_size is rejected with a clear error rather than misread.
New surface:
dfine_options_t:gpu_decode,own_device_memory,full_pipeline_graph, and letterbox
preprocessing (resize,letterbox_topleft,letterbox_pad,letterbox_no_upscale).dfine_detector_freeze(det, spec)— warm to peak + lock (zero steady-state allocation);
captures the full-pipeline CUDA graph when requested.dfine_freeze_spec_tcarries
batch / source size / channel order.dfine_detector_full_graph_active(det)— observability for the single-launch path.dfine_detector_last_timings(det, out)— per-stage wall/CPU times;dispatch_msis the
host cost the graph collapses.
Python
Everything above is now reachable from the ctypes bindings: Detector(gpu_decode=, own_device_memory=, full_pipeline_graph=, letterbox=, letterbox_topleft=, letterbox_pad=, letterbox_upscale=), Detector.freeze(batch, src_w=, src_h=, src_is_bgr=),
Detector.full_pipeline_graph_active, Detector.last_timings(). Measured from Python on the
m FP16 0-aux engine: graph active, dispatch_ms ≈ 0.08 per frame.
Also in this release
- Upstream D-FINE-seg TRT export re-verification recorded in
docs/impl/DFINE_SEG_TRT_BUG_REPORT.md(the author's own static-b1 flow loses 12.4 AP in
FP16 and 18.0 AP in FP32 while its ONNX matches torch; this runtime's explicit-deform export
is the fix).
Validation
C-ABI smoke extended with the v2 contract checks (zero struct_size rejection, freeze(NULL),
re-freeze idempotence, timings fill); byte-parity C++ ↔ C ABI PASS; 14/14 pytests; default-path
detections remain byte-identical to v0.1.0.
Artifacts
Same layout as v0.1.0: dfine_{n,s,m,l,x}[_fp16_st].onnx + .json sidecars + SHA256SUMS +
dfine-0.2.0-py3-none-linux_x86_64.whl (sm_89; needs local TensorRT 10.x + CUDA 12) + demo mp4s.
SONAME
The shared library SONAME moved from libdfine.so.0 to libdfine.so.1 with this ABI break, so
pre-0.2.0 binaries fail at load (clean "cannot open shared object" error) instead of misreading the
new options layout.
v0.1.0 — first public release
D-FINE-cpp v0.1.0
C++/TensorRT inference runtime for the D-FINE object detector. First public release.
Highlights
- Correct on TensorRT. The explicit gather-bilinear deformable-attention export fixes a −10.5 AP
trap in the stockgrid_sampleexport (TRT compiles it divergently in-context). No plugin, no
latency cost; full-val mAP matches PyTorch to ≤0.001 AP on all five model sizes. - FP16 that holds mAP. Strongly-typed FP16 (precision baked into ONNX types, decoder kept FP32):
−0.2% mAP worst case at 1.3–2.8× the FP32 throughput. The weakly-typedkFP16builder flag loses a
fixed 6.8 AP on D-FINE and is not used. - Frozen single-launch pipeline (intensive-core P1–P3). Opt-in
gpu_decode(Zero-D2H decode on
device),freeze()/FreezeSpec(zero steady-state allocation, VRAM Δ = +0 B over full runs), and
full_pipeline_graph: H2D → preprocess → inference → decode → D2H replayed as one
cudaGraphLaunchper frame. Byte-identical to the split path on all five sizes (validated on real
640×480 COCO images); CPU cost per frame drops to 0.2–0.9 ms (batch-1 dispatch ≈ 0.1 ms). - Bindings. Stable C ABI (opaque handle, thread-local errors) and a dependency-light Python
ctypespackage +dfineCLI; detections byte-identical to the C++ binary (pytest-verified).
Custom label sets ride the.jsonsidecar end to end (class_names). - Optional letterbox preprocessing.
PreprocessSpec(options or sidecarresizefield):
anchor center/topleft, padding value, upscale on/off; boxes are un-mapped and clipped
automatically, works with the GPU decode and the full-pipeline graph (byte-parity verified).
Stretch stays the default — it is the training convention and measures ~1.7–2.0 AP better on the
published weights (trt-files/scripts/letterbox_eval.py); the native CUDA path reproduces the
host references to +0.0002 AP.
Numbers (RTX 4070 Ti SUPER, COCO val2017 full, e2e)
| size | C++ FP16 FPS b1 / b8 | mAP (PyTorch ref) |
|---|---|---|
| nano | 453 / 1206 | 0.4280 (0.4279) |
| small | 346 / 638 | 0.5069 (0.5073) |
| medium | 281 / 442 | 0.5500 (0.5509) |
| large | 228 / 358 | 0.5723 (0.5724) |
| xlarge | 180 / 246 | 0.5927 (0.5931) |
Full cross-backend tables (PyTorch / ONNXRuntime-GPU / TensorRT-Python / C++), the CUDA-graph and
full-pipeline-graph comparisons, and the per-config mAP matrix are reproducible with
trt-files/scripts/overnight_bench.sh.
Artifacts
dfine_{n,s,m,l,x}.onnx+dfine_{n,s,m,l,x}_fp16_st.onnx— ready-to-build ONNX exports (raw
two-output graph, explicit deform core) with.jsonsidecars. Engines are GPU-arch/TRT-version
specific: build locally withtrt-files/scripts/build_engine.py(see README Quickstart).SHA256SUMS— checksums for every artifact.dfine-0.1.0-py3-none-linux_x86_64.whl— Python package with bundledlibdfine.so(sm_89; needs
local TensorRT 10.x + CUDA 12 at runtime).- Demo clips (mp4): side-by-side throughput comparisons rendered by
make_demo_gif.py.
Requirements
Linux x86_64, NVIDIA GPU, CUDA 12.x, TensorRT 10.x (validated on 10.13), CMake ≥ 3.24 for
CUDA_ARCHITECTURES=native (≥ 3.20 with an explicit arch). No OpenCV.
Known limitations
- Detection only (instance segmentation shelved — no pretrained seg checkpoints).
- INT8/BF16 rejected: D-FINE's FDR box decode needs FP16-or-better mantissa precision (measured, see
README precision guide). - The C ABI does not yet expose
gpu_decode/freeze/full_pipeline_graph(C++-only for now). - Wheel is linux_x86_64/sm_89; other platforms build from source.