Add model type and input-resolution usage telemetry - #2782
Conversation
Decorate doctr, grounding_dino, yolo_world, and owlv2 infer paths so they emit model-category telemetry rows, and resolve OwlV2 (h, w) input sizes. Co-authored-by: Cursor <cursoragent@cursor.com>
|
👋 Thanks for the pull request! Here is how automated Claude review works here, so you spend credits (and reviewer time) wisely. 🚦 This PR is marked Ready for review, so automated Claude review will run — and every pass spends real credits. Warning 💸 The Claude reviewer bills in credits, not vibesAutomated review spins up a real agent that reads real code and spends real credits on every pass. It is glad to help — but it is not a rubber duck, a linter you poke in a loop, or a substitute for reading the contributing guide. Treat it like an expensive senior reviewer whose time you booked, and show up prepared. Draft when unsure, Ready when you mean it:
However you get there, arrive prepared:
Reviews are not free. A draft costs nothing to review; a Ready PR is a promise that it is worth reviewing.
|
|
🤖 Claude review started at commit New commits are not auto-reviewed. Add the |
|
@SolomonLake — thanks for this. The telemetry plumbing is carefully built (ContextVar isolation across worker threads, bounded process-local model-type map off the hot path, batch-padding excluded from frame counts, adapter/backend input-size resolution) and the test coverage is strong. I found no hard blocker, but two questions materially affect the outcome and I can't resolve either from this repo alone. Warning ⏳ This PR is on hold pending your answers. The review will not advance to sign-off and the PR should not proceed to merge until the IMPORTANT questions below are answered. IMPORTANT — please answer
Notes (non-blocking)
Re-review is not automatic: once you've answered and/or pushed changes, add the Reviewed at HEAD: 7422b58 |
last_request can be overwritten by concurrent empty-query POSTs from the usage sender, which made model-type tests flake under full CI. Co-authored-by: Cursor <cursoragent@cursor.com>
Yes, this is intentional. And I have ensured this will not result in double counting.
Yes, the ingestion endpoint has been updated to accept these fields. And that separate offloader will be updated after these changes are merged. |
|
🤖 Claude review started at commit New commits are not auto-reviewed. Add the |
|
@SolomonLake — thanks for the answers, and for the follow-up commit hardening the roboflow-API query assertions against background usage POSTs ( Warning ⏳ This PR is still on hold pending one clarification. The review will not advance to sign-off until the billing/quota point below is confirmed. New commits since the last review were the test-hardening commit and a no-op merge of Status of the earlier IMPORTANT questions
IMPORTANT — please confirm (needs a concrete answer, ideally with maintainer sign-off) On the platform billing/quota side, are Escalation to code-owners @PawelPeczek-Roboflow @grzegorz-roboflow @dkosowski87 — this PR changes what is recorded on billable usage rows: Non-blocking notes (carried forward, unchanged)
Re-review is not automatic: once you have answered and/or pushed changes, add the Reviewed at HEAD: 642f621 |
On our Cloud APIs we do not bill for processed frames for workflows AND model lines. This would result in double billing. For legacy plans that bill on a per image basis, we only look at request rows. For usage credit based plans we only look at execution time, not processed frames. |
Co-authored-by: Cursor <cursoragent@cursor.com>
What does this PR do?
Extends usage telemetry so each model call can be attributed by Roboflow
modelType(for examplerfdetr-seg-nano) and by the post-preprocess / fixed model input resolution, bucketed in megapixels. Today usage rows identify a databaseresource_idbut not the architecture/size, and they do not record the resolution the model actually ran at — which makes per-model and per-resolution analysis incomplete, especially for streams.Model rows now include
resource_details.model_typefrom a process-local cache populated when the registry resolves a model type at load time (so the usage decorator never does a registry/network lookup on the hot path). They also accumulatemegapixel_bucketskeyed by ranges such as0.25-0.5, storing summedprocessed_framesandexecution_durationper bucket. Fixed-input models use their configured size; dynamic models publish measured post-preprocess size via aContextVarso concurrentinfer()calls stay isolated. Frame counts come from the request image list rather than the padded tensor batch. SAM entrypoints that decorateinfer_from_requestpublish encoder size explicitly. Families that overrideinfer()without callingsuper()(doctr, grounding_dino, yolo_world, owlv2, includinginference_modelsadapters) now decorate their owninfer()so they emit model-category telemetry instead of being missing from per-model coverage.Main elements:
inference/usage_tracking/megapixel_buckets.py— bucketing, measured-input context, fixed-size resolutioninference/usage_tracking/model_types.py— process-local model id →modelTypemapinference/usage_tracking/decorator_helpers.py/collector.py/payload_helpers.py— extract, record, and merge bucketsinferpaths that publish or decorate usagetests/inference/unit_tests/usage_tracking/Type of Change
Testing
Unit tests
infer()for model telemetry(height, width)and wrapped-backend fixed-size resolutionIntegration tests
Other
uv run pytest tests/inference/unit_tests/usage_tracking/ -quv run pytest tests/inference/unit_tests/models/ -quv run black/uv run isorton touched pathsChecklist
Additional Context
megapixel_buckets.model_typeis nested under existingresource_detailsand needs no new top-level column./usage/inferencecurrently rebuilds payloads from an allowlist and will dropmegapixel_bucketsuntil that handler (and the BigQueryinference_usageschema) accept the field.model_typealready survives viaresource_details.unknownmegapixel bucket when native arrays are passed into libraries that resize internally; OwlV2 reports a real fixed input size.category="model"telemetry rows (workflow-routed calls were already covered by workflow rows).Required follow-up: Redis / Dragonfly usage offloader
Serverless paths with
REDIS_HOSTstore-and-forget into aUsageCollectorsorted set; an external offloader (aws_lambdas/inference-usage-collector-redis-offload, also deployed as the Crusoeusage-collectorCronJob against Dragonfly) drains andzip_usage_payloads-merges those rows. It loadspayload_helpers.pyfrom a pinnedinferencewheel (currently0.49.5), which does not summegapixel_buckets— conflicting merges last-writer-win instead.This is required after this PR ships (in-process collector merge alone is not enough for Redis/Dragonfly traffic):
inferenceversion that includes this PR’smerge_megapixel_buckets/merge_usage_dictschanges.aws_lambdas/inference-usage-collector-redis-offload/Dockerfile, bumpinference==…to that release.src/version.py, rebuild/push the image (GAR for Crusoe CronJob; ECR if the AWS Lambda path is still live).inference_usage_collector_redis_offload_versionin tfvars if applicable) and deploy.Until that pin moves, Redis/Dragonfly zip-merge undercounts or overwrites
megapixel_buckets. Non-Redis paths (local / SQLite) are fine once this PR is deployed.Made with Cursor