Profile Image Understanding with AIPerf
This example uses Qwen3-VL-2B-Instruct. First follow
Build from Source and
Build a Bundle, using the existing
Qwen3-VL-2B profile.
Include the trtmc_model_qwen_vl runtime target and run the family's correctness
checks. The commands below assume qwen3-vl-2b.bundle is already built and
trtmc-server is on PATH.
Build Qwen-VL bundles with the current builder: it preserves image aspect ratios with smart resize, using the existing resize targets (nominally 196 image tokens for Qwen3-VL, 256 for Qwen2.5-VL). Dynamic profiles also admit upstream rounding at extreme aspect ratios. Older bundles that force every image into a square should be rebuilt before qualification.
Run from the TRTMC checkout in your prepared GPU environment. In Docker, open both terminals in the same container.
1. Install the client and prepare a question
python -m pip install -e '.[serve]' -C py-only=true
python -m venv .venv-aiperf
.venv-aiperf/bin/pip install aiperf==0.13.0
.venv-aiperf/bin/python apps/aiperf_qual/examples/prepare_vision_input.py \
--image families/qwen_vl/tests/data/test_img.jpeg \
--prompt 'What color is the vehicle in this image? Answer in one word.' \
--output /tmp/aiperf-vision.jsonl
The input contains the original image bytes and the question. The client comes from PyPI; no AIPerf source checkout is needed.
2. Start the model (terminal 1)
trtmc-server ./qwen3-vl-2b.bundle --model-name Qwen/Qwen3-VL-2B-Instruct \
--records artifacts/aiperf-vision-server.jsonl
Wait for Uvicorn running on http://127.0.0.1:8000. Use the full binary path
and --runtime-root if your native libraries are in a separate directory.
3. Run AIPerf (terminal 2)
.venv-aiperf/bin/aiperf profile \
--url http://127.0.0.1:8000 --model Qwen/Qwen3-VL-2B-Instruct \
--tokenizer-revision 89644892e4d85e24eaac8bacfd4f463576704203 \
--endpoint-type chat --endpoint /v1/chat/completions \
--input-file /tmp/aiperf-vision.jsonl --custom-dataset-type single_turn \
--extra-inputs max_tokens:10 temperature:1.0 top_k:1 \
--concurrency 1 --warmup-request-count 5 --request-count 50 \
--random-seed 0 --ui-type simple --export-level raw \
--artifact-dir artifacts/aiperf-vision
Each request sends one image and one question, then receives a complete answer.
Read request latency and request throughput in profile_export_aiperf.json.
This is a nonstreaming workload: token TTFT and inter-token latency are not
qualified. Server records preserve request identity, image dimensions and bytes,
output-token counts, and model_call_ms under public_task_call_wall.
Task time includes family preprocessing and generation; transport image decoding
is outside it. Keep Task time separate from client latency. Build, load, startup,
and warmup are excluded from steady-state measurements.
Client token counts are estimates; image prompt-token counts are unavailable.
Server records retain the actual native output-token counts.
Run another built model
Replace the bundle, API model name, tokenizer revision, image, question, and output-token limit.
Use that family's build guidance and correctness checks. The bundle must declare
vision_language_generation or SDK images_text_to_text; a text-only bundle from the same checkpoint does
not qualify. Image preprocessing and prompt templates remain owned by the family.
Rebuild older DeepSeek-OCR-2 bundles to use aspect-preserving padding with the current family runtime before qualification. Rebuild older native InternVL3 bundles to include the checkpoint processor's image-token delimiters.
Native InternVL builds follow the checkpoint processor's image tiling (up to
12 local tiles plus a thumbnail). Use --max-sequence-length 4096 to leave room
for those visual tokens and the answer. Rebuild older single-view bundles with
the current family runtime before qualification.
For a local tokenizer, omit --tokenizer-revision and add
--tokenizer /path/to/tokenizer to AIPerf. For Lance, run this once in its
prepared family environment:
python families/lance/tests/aiperf/prepare_tokenizer.py \
--model-dir /path/to/Lance --output-dir /tmp/lance-tokenizer
Then use --tokenizer /tmp/lance-tokenizer. The automated endpoint-profile
runner accepts the same option and pins the default tokenizer to the manifest's
checkpoint revision.
For Phi4, use families/phi4_multimodal/tests/aiperf/prepare_tokenizer.py with
the same flags, then pass its output directory with --tokenizer.
The endpoint accepts one user message containing text and one embedded RGB
PNG/JPEG image. It rejects multi-image inputs, multi-turn conversations, system
prompts, streaming, stop sequences, and thinking controls. The server does not
fetch remote image URLs or open client-provided paths. Defaults allow 16 million
pixels and a 1 MiB request; raise --max-body-bytes when base64 image data exceeds
that limit.