| sidebar-title | SGLang Image Edit |
|---|
This guide shows how to benchmark image-to-image (TI2I) APIs using a Docker-based server and AIPerf. You'll learn how to:
- Set up the server (FLUX.2-Klein-4B on SGLang)
- Run the benchmark with synthetic reference images or your own input file
- View the results and extract the edited images
The endpoint follows the OpenAI Image Edit shape: prompt + reference image are POSTed to /v1/images/edits as multipart/form-data. AIPerf auto-defaults request_content_type to multipart for image_edit, so you don't need to pass --request-content-type explicitly.
For the most up-to-date information, please refer to the following resources:
- OpenAI Image Edit API
- SGLang Multimodal Gen —
/v1/images/editsroute - FLUX.2-Klein-4B on Hugging Face
Login to Hugging Face, and accept the terms of use for FLUX.2-Klein-4B.
Export your Hugging Face token as an environment variable:
export HF_TOKEN=<your-huggingface-token>Start the Docker container:
docker run --gpus all \
--shm-size 32g \
-it \
--rm \
-p 30000:30000 \
-v ~/.cache/huggingface:/root/.cache/huggingface \
--env "HF_TOKEN=$HF_TOKEN" \
--ipc=host \
lmsysorg/sglang:devNote
The following steps are to be performed inside the Docker container. lmsysorg/sglang:dev ships the diffusion stack ready to run — no extra pip install step is needed for FLUX.2-Klein-4B.
Set the server arguments:
Warning
These arguments set up FLUX.2-Klein-4B on a single GPU at port 30000. Adjust the model path, GPU count, or port to match your environment. The flags below come from upstream SGLang multimodal_gen and may change over time — treat the SGLang Multimodal Gen CLI as the source of truth if any flag here is rejected.
SERVER_ARGS=( --model-path black-forest-labs/FLUX.2-klein-4B --num-gpus 1 --port 30000 --host 0.0.0.0 --warmup --enable-torch-compile )Start the server:
sglang serve "${SERVER_ARGS[@]}"Wait until the server is ready (watch the logs for the following message):
Uvicorn running on http://0.0.0.0:30000 (Press CTRL+C to quit)Note
The following steps are to be performed on your local machine (outside the Docker container).
The simplest path: AIPerf generates a synthetic reference image for every request and pairs it with a synthetic prompt. The mock image bytes are uploaded as the multipart image field — the server processes the request end-to-end just like a real one.
aiperf profile \
--model black-forest-labs/FLUX.2-klein-4B \
--tokenizer gpt2 \
--url http://localhost:30000 \
--endpoint-type image_edit \
--image-batch-size 1 \
--image-width-mean 512 \
--image-height-mean 512 \
--extra-inputs size:512x512 \
--extra-inputs num_inference_steps:4 \
--extra-inputs guidance_scale:1.0 \
--warmup-request-count 5 \
--request-count 50 \
--concurrency 2Done! This sends 50 requests to http://localhost:30000/v1/images/edits with multipart-encoded prompt + reference image, plus diffusion-specific extras (size, num_inference_steps, guidance_scale).
Sample Output (shape only — exact numbers will depend on your hardware):
NVIDIA AIPerf | Image Edit Metrics
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━┳━━━━━┳━━━━━┳━━━━━┳━━━━━┳━━━━━┳━━━━━┓
┃ Metric ┃ avg ┃ min ┃ max ┃ p99 ┃ p90 ┃ p50 ┃ std ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━╇━━━━━╇━━━━━╇━━━━━╇━━━━━╇━━━━━╇━━━━━┩
│ Request Latency (ms) │ ... │ ... │ ... │ ... │ ... │ ... │ ... │
│ Input Sequence Length (tokens) │ ... │ ... │ ... │ ... │ ... │ ... │ ... │
│ Image Throughput (images/sec) │ ... │ ... │ ... │ ... │ ... │ ... │ ... │
│ Image Latency (ms/image) │ ... │ ... │ ... │ ... │ ... │ ... │ ... │
│ Request Throughput (requests/sec) │ ... │ N/A │ N/A │ N/A │ N/A │ N/A │ N/A │
│ Request Count (requests) │ ... │ N/A │ N/A │ N/A │ N/A │ N/A │ N/A │
└───────────────────────────────────┴──────┴─────┴─────┴─────┴─────┴─────┴─────┘
For deterministic prompt + reference image sequences, use a JSONL input file. Each line must include both the prompt (text) and the reference image (image, a local path or URL) — the image_edit endpoint rejects turns without a reference image, and the single_turn loader does not synthesize one.
Create an input file (replace the paths/URLs with real reference images you want to edit):
cat > edit_prompts.jsonl << 'EOF'
{"text": "Convert this scene to a watercolor painting", "image": "/path/to/ref1.png"}
{"text": "Make the background a sunset", "image": "/path/to/ref2.png"}
{"text": "Add snow to the trees", "image": "https://example.com/ref3.png"}
EOFRun the benchmark:
aiperf profile \
--model black-forest-labs/FLUX.2-klein-4B \
--tokenizer gpt2 \
--url http://localhost:30000 \
--endpoint-type image_edit \
--input-file edit_prompts.jsonl \
--custom-dataset-type single_turn \
--extra-inputs size:512x512 \
--extra-inputs num_inference_steps:4 \
--concurrency 1 \
--request-count 3Image edit shares its metric set with image generation; both endpoints report image-level throughput/latency on top of the standard request-level metrics. There are no token-streaming metrics (TTFT, ITL) because the edited image is returned as a single response.
| Metric | Description |
|---|---|
| Request Latency (ms) | End-to-end time per request — from sending the multipart body to receiving the edited image. |
| Input Sequence Length (tokens) | Token count of the prompt portion only; the reference image is uploaded separately as binary and does not contribute. |
| Image Throughput (images/sec) | Number of edited images returned per second across all concurrent workers. |
| Image Latency (ms/image) | Per-image latency; equals request latency when each request returns one image. |
| Request Throughput (requests/sec) | Sustained request rate. |
| Request Count (requests) | Total completed requests. |
Tip
The first request typically pays a torch.compile cold-start cost (multiple seconds). Use --warmup-request-count to exclude warmup requests from the reported metrics.
Use --export-level raw to capture the raw input/output payloads, which lets you extract the edited images afterwards.
aiperf profile \
--model black-forest-labs/FLUX.2-klein-4B \
--tokenizer gpt2 \
--url http://localhost:30000 \
--endpoint-type image_edit \
--input-file edit_prompts.jsonl \
--custom-dataset-type single_turn \
--extra-inputs size:512x512 \
--extra-inputs num_inference_steps:4 \
--concurrency 1 \
--request-count 3 \
--export-level rawThe edited images come back as base64 strings inside each response. You can reuse the same extraction script from the Image Generation tutorial — the response shape is identical. Point it at the image_edit artifacts directory:
python extract_images.py \
artifacts/black-forest-labs_FLUX.2-klein-4B-openai-image_edit-concurrency1/profile_export_raw.jsonl \
extracted_editsYou've set up an image-to-image diffusion server, benchmarked it with both synthetic and file-driven prompts, and seen the metric set AIPerf reports for image_edit. From here you can sweep over num_inference_steps, guidance_scale, resolution, or concurrency to map the perf trade-offs of your model and hardware.