Image generation telemetry: eight models, two cloud GPUs, 506 images
Eight open-weight text-to-image models, 506 completed requests, two rented AWS GPU instances, all run through Marigold. Each request recorded inference time, VRAM allocated and peak, mean and peak power draw, and model load time.
Per-step inference time drives the time and cost figures. It is linear in step count, spans 0.008 to 2.534 s/step across the set (over 300-fold), follows architecture more closely than parameter count, and is unchanged by prompt length. Classifier-free guidance multiplies it by 1.7 to 2.1 on the A10G and by 1.0 to 1.5 on the RTX PRO 6000. Cost per image is that time multiplied by an hourly instance rate, and runs from 0.00026 to 0.036 USD.
Setup
Two instances, both in eu-west-2, both running the same Marigold 0.6.10 Docker Compose stack: Postgres for the queue, one worker process, model weights on an EBS volume that survives the instance (the benchmark and the Terraform are public; links at the end).
g5.4xlarge NVIDIA A10G 22.06 GiB usable VRAM, 64 GiB host
g7e.4xlarge NVIDIA RTX PRO 6000 96 GiB VRAM, 128 GiB host
The A10G run completed 200 requests across four models. The RTX PRO 6000 run completed 306 across six.
The model cache is an EBS volume attached to whichever instance is running. It held 96 GB of weights for the first run and was reused by the second, so load times below are warm-cache figures.
Methodology
Each model receives the same parameter sweep, submitted serially through the HTTP API and polled to completion. The worker holds one model resident at a time and switches on queue depth, so requests are grouped by model and never interleaved.
steps 1, 4, 8, 16, 25, 40, 100, 200 (set varies by run)
guidance 0.0, 1.0, 3.5, 7.5, 15.0
prompt 8, 30, 90 and 220 CLIP tokens (second run only)
seed fixed at 20260910 throughout
resolution each model's native default
One warm-up request per model is recorded and excluded from the figures below. The first request after a load ran up to 75 times slower than later ones on one model and no slower on another.
Five repeats of each cell on the first run gave a median coefficient of variation of 0.02 per cent, and the mean of the first three matched the mean of all five with a median error of zero. Inference time on a dedicated GPU with a fixed seed is repeatable to three decimal places.
Models
| model | architecture | weights | native |
|---|---|---|---|
| idkiro/sdxs-512-dreamshaper | distilled SD 1.5 unet | 0.63 GB | 512 |
| dream-textures/texture-diffusion | SD 1.5 unet fine-tune | 1.73 GB | 512 |
| arrexel/pattern-diffusion | SD 2.0 unet fine-tune | 1.73 GB | 512 |
| efficient-large-model/sana_600m | linear-attention DiT | 1.18 GB | 1024 |
| efficient-large-model/sana_1600m | linear-attention DiT | 3.21 GB | 1024 |
| stabilityai/stable-diffusion-xl-base-1.0 | unet | 5.13 GB | 1024 |
| black-forest-labs/flux.1-schnell | DiT, T5 encoder | 5.95 GB (NF4) | 1024 |
| tongyi-mai/z-image-turbo | DiT | 12.31 GB | 1024 |
Weights are the loaded footprint reported by the handler. On disk, FLUX occupies 33.7 GB and z-image 32.9 GB. z-image-turbo returned blank images throughout, so its figures describe the computation as run.
Per-step cost
Inference time is linear in step count across the whole sweep, with a fixed overhead per request. Fitting across every step value at guidance 7.5:
| model | hardware | s/step | fixed | it/s |
|---|---|---|---|---|
| sdxs-512-dreamshaper | RTX PRO 6000 | 0.008 | 0.01 | 127.8 |
| texture-diffusion | RTX PRO 6000 | 0.017 | 0.04 | 57.5 |
| pattern-diffusion | RTX PRO 6000 | 0.017 | 0.04 | 57.7 |
| sana_600m | RTX PRO 6000 | 0.026 | 0.13 | 38.5 |
| sana_1600m | RTX PRO 6000 | 0.032 | 0.12 | 31.7 |
| flux.1-schnell (fp16) | RTX PRO 6000 | 0.322 | 0.17 | 3.1 |
| sana_1600m | A10G | 0.157 | 0.76 | 6.4 |
| stable-diffusion-xl-base-1.0 | A10G | 0.289 | 0.64 | 3.5 |
| flux.1-schnell (NF4) | A10G | 1.675 | 0.63 | 0.6 |
| z-image-turbo | A10G | 2.534 | 0.62 | 0.4 |
The fixed term is the VAE decode: 0.62 to 0.76 seconds on the A10G for all four models, and 0.01 to 0.17 on the larger card. It puts a floor under the cost of short runs.
Sana 1600M is the only model measured identically on both cards. It takes 0.157 s/step on the A10G and 0.032 on the RTX PRO 6000, a factor of 4.9.
Model size and per-step cost
Sana 600M and Sana 1600M share an architecture, a text encoder and a native resolution. On the same card:
sana_600m 1.18 GB weights 0.0259 s/step
sana_1600m 3.21 GB weights 0.0316 s/step
The larger model has 2.7 times the weights and costs 1.23 times as much per step. Memory follows the same pattern, at 9.10 GB allocated against 7.07, a ratio of 1.29.
Across families the relationship weakens further. z-image-turbo carries 12.31 GB of weights and runs at 2.534 s/step. FLUX carries 5.95 GB quantised and runs at 1.675. SDXL, at 5.13 GB, runs at 0.289, nearly six times faster than FLUX at a similar loaded size. Per-step time in this set follows architecture more closely than weight size.
Seconds per step against loaded weight size at guidance 7.5, one panel per card. The two 1.73 GB models on the RTX PRO 6000 coincide.
Classifier-free guidance cost depends on the card
Guidance above a threshold runs two forward passes per step on a doubled batch, which predicts a doubling of inference time. On the A10G the ratio falls between 1.74 and 2.08 for the three models that use it:
| model | cfg 0.0 | cfg 7.5 | ratio |
|---|---|---|---|
| stable-diffusion-xl-base-1.0 | 4.50 s | 7.85 s | 1.74 |
| sana_1600m | 2.40 s | 4.40 s | 1.83 |
| z-image-turbo | 30.82 s | 63.95 s | 2.08 |
| flux.1-schnell | 42.46 s | 42.46 s | 1.00 |
On the RTX PRO 6000 the ratio is close to 1.0 for every model except Sana 1600M:
| model | cfg 0.0 | cfg 7.5 | ratio |
|---|---|---|---|
| sdxs-512-dreamshaper | 0.21 s | 0.21 s | 1.01 |
| pattern-diffusion | 0.47 s | 0.47 s | 0.99 |
| texture-diffusion | 0.47 s | 0.47 s | 1.02 |
| sana_600m | 0.73 s | 0.78 s | 1.06 |
| sana_1600m | 0.60 s | 0.91 s | 1.52 |
| flux.1-schnell | 8.22 s | 8.22 s | 1.00 |
Inference time at guidance 7.5 divided by inference time at guidance 0.0, 25 steps. RTX is the RTX PRO 6000.
Sana 1600M is the one model present in both runs at the same resolution with the same request: 1.83 on the A10G, 1.52 on the RTX PRO 6000. The doubled batch costs less when the card has capacity to process both halves concurrently.
Sana 600M on the larger card shows 1.06. A smaller model occupies less of the card, so the second pass has more room. The three 512px models, run only on the larger card, show 0.99 to 1.02.
On the A10G a guidance setting roughly doubles inference time. On the RTX PRO 6000 it adds between 0 and 52 per cent.
FLUX.1-schnell is flat at 1.00 across all five guidance values on both cards (it is a distilled model and runs a single forward pass per step).
Prompt length
Four prompt lengths at 25 steps and guidance 7.5, from a single sentence to a paragraph of roughly 220 CLIP tokens (the CLIP encoders truncate at 77 tokens, so the 90 and 220 token prompts reach those models cut short):
| model | 8 tok | 30 tok | 90 tok | 220 tok | spread |
|---|---|---|---|---|---|
| sdxs-512-dreamshaper | 0.207 | 0.207 | 0.207 | 0.207 | 0.2% |
| pattern-diffusion | 0.466 | 0.463 | 0.467 | 0.467 | 1.0% |
| texture-diffusion | 0.471 | 0.476 | 0.473 | 0.472 | 1.1% |
| sana_600m | 0.772 | 0.776 | 0.780 | 0.774 | 1.0% |
| sana_1600m | 0.915 | 0.913 | 0.914 | 0.915 | 0.1% |
| flux.1-schnell | 8.218 | 8.218 | 8.219 | 8.221 | 0.0% |
The spread is at most 1.1 per cent. CLIP-based models were expected to be flat because CLIP truncates, and the T5 and Gemma encoders to scale with input. FLUX uses T5 and shows a spread of 0.0 per cent. Sana uses Gemma and shows 0.1 to 1.0.
The text encoder runs once per request against a denoising loop of 25 iterations, and even a T5-XXL pass disappears into that (in LLM inference, prompt length drives both time and memory).
Memory
| model | hardware | weights | allocated | peak |
|---|---|---|---|---|
| sdxs-512-dreamshaper | RTX PRO 6000 | 0.63 | 0.92 | 1.08 |
| texture-diffusion | RTX PRO 6000 | 1.73 | 2.61 | 3.25 |
| sana_600m | RTX PRO 6000 | 1.18 | 7.07 | 8.82 |
| sana_1600m | RTX PRO 6000 | 3.21 | 9.10 | 10.85 |
| sana_1600m | A10G | 3.21 | 9.07 | 10.82 |
| stable-diffusion-xl-base-1.0 | A10G | 5.13 | 6.95 | 11.14 |
| flux.1-schnell | both | 5.95 | 13.45 | 16.03 |
| z-image-turbo | A10G | 12.31 | 20.53 | 23.09 |
Figures in GB. Peak is the allocator high-water mark during inference.
Allocation follows the model and the request wherever there is headroom. Sana 1600M allocates 9.10 GB on the 96 GB card and 9.07 on the 22 GB card, and FLUX peaks at 16.03 on both.
z-image-turbo peaks at 23.09 GB against 22.06 GiB usable, with allocator warnings throughout, and is the slowest model in the set at 2.534 s/step.
FLUX in fp16 does not fit the A10G. The load reached 21.80 GiB allocated against 22.06 GiB usable and stopped 108 MiB short, about half a per cent. The A10G figures above use NF4 quantisation, which brings the loaded footprint to 5.95 GB and the peak to 16.03.
Power and energy
| model | hardware | mean W | peak W | mWh/image |
|---|---|---|---|---|
| sdxs-512-dreamshaper | RTX PRO 6000 | 98.0 | 232.4 | 7.9 |
| pattern-diffusion | RTX PRO 6000 | 141.9 | 386.9 | 18.8 |
| texture-diffusion | RTX PRO 6000 | 150.1 | 388.9 | 22.4 |
| sana_600m | RTX PRO 6000 | 188.4 | 384.7 | 49.6 |
| sana_1600m | RTX PRO 6000 | 282.1 | 572.6 | 96.1 |
| flux.1-schnell | RTX PRO 6000 | 498.4 | 574.3 | 1242.9 |
| z-image-turbo | A10G | 185.7 | 200.4 | 3304.4 |
| sana_1600m | A10G | 214.4 | 262.6 | 294.2 |
| stable-diffusion-xl-base-1.0 | A10G | 236.6 | 272.7 | 554.3 |
| flux.1-schnell | A10G | 239.5 | 251.1 | 2868.3 |
Energy per image is at 25 steps, guidance 7.5.
Mean power on the A10G stays between 185 and 240 W across four models of very different sizes, with no peak above 273 W on a 300 W card. That agrees with the guidance results: these workloads occupy the card fully. On the RTX PRO 6000 mean power spans 98 to 498 W and rises with model size, because nothing in this set fills that card.
Mean power depends on run length. A short request ends before the card reaches steady state, which lowers the mean. The 0.21 s sdxs request is one of these.
Load time
Warm cache, weights already on the EBS volume:
| model | A10G | RTX PRO 6000 |
|---|---|---|
| texture-diffusion | – | 0.7 s |
| pattern-diffusion | – | 2.2 s |
| sdxs-512-dreamshaper | – | 5.9 s |
| flux.1-schnell | 128.8 s | 8.1 s |
| sana_600m | – | 34.6 s |
| sana_1600m | 51.4 s | 50.5 s |
| stable-diffusion-xl-base-1.0 | 53.0 s | – |
| z-image-turbo | 128.2 s | – |
Load time is reported once per loaded model and copied to every request that model serves, so it cannot be averaged into a per-image figure.
The worker holds one model at a time and unloads on switching. A mixed-model workload pays the load time on every switch: the four A10G models sum to just over six minutes, and the six RTX PRO 6000 models to just under two. A deployment serving one model pays once.
FLUX loaded in 8.1 seconds on the second run against 128.8 on the first. The difference is largely host page cache (the second run had the weights in memory from a preceding request).
Cost per image
At 25 steps and guidance 7.5, assuming continuous utilisation, at approximate on-demand eu-west-2 rates of 2.03 USD per hour for the g5.4xlarge and 4.50 USD for the g7e.4xlarge:
| model | hardware | seconds | USD/image | images/hour |
|---|---|---|---|---|
| sdxs-512-dreamshaper | RTX PRO 6000 | 0.21 | 0.00026 | 17,400 |
| pattern-diffusion | RTX PRO 6000 | 0.47 | 0.00058 | 7,700 |
| sana_600m | RTX PRO 6000 | 0.78 | 0.00097 | 4,600 |
| sana_1600m | RTX PRO 6000 | 0.91 | 0.00114 | 3,900 |
| sana_1600m | A10G | 4.40 | 0.00248 | 818 |
| stable-diffusion-xl-base-1.0 | A10G | 7.85 | 0.00443 | 458 |
| flux.1-schnell | RTX PRO 6000 | 8.22 | 0.01027 | 438 |
| flux.1-schnell | A10G | 42.46 | 0.02394 | 85 |
| z-image-turbo | A10G | 63.95 | 0.03606 | 56 |
Instance cost per image at 25 steps and guidance 7.5, assuming continuous utilisation. RTX is the RTX PRO 6000.
Cost per image scales with the inverse of utilisation. At 10 per cent utilisation each figure is ten times higher.
FLUX takes 42.46 seconds at 25 steps on the A10G (NF4) and 8.22 on the RTX PRO 6000 (fp16), a factor of 5.2. The RTX PRO 6000 instance costs about 2.2 times as much per hour, so each image costs 43 per cent as much (0.01027 against 0.02394 USD).
Summary
Per-step inference time is linear in step count and repeatable to three decimal places, so two points on a card recover it. It spans 0.008 to 2.534 s/step across the set, and the Sana pair gives 2.7 times the weights for 1.23 times the per-step time. Prompt length changes inference time by at most 1.1 per cent across a 27-fold range of tokens. Guidance multiplies inference time by 1.7 to 2.1 on the A10G and by 1.0 to 1.5 on the RTX PRO 6000, with FLUX at 1.0 on both. At 25 steps and guidance 7.5, cost per image runs from 0.00026 to 0.036 USD at continuous utilisation.
Raw data
[
{"model":"black-forest-labs/flux.1-schnell","hw":"a10g","s_per_step":1.6745,"fixed_s":0.631,"it_per_s":0.6,"weights_gb":5.95,"vram_gb":13.44,"vram_peak_gb":16.0,"w_mean":239.5,"w_peak":251.1,"load_s":128.8,"cfg_ratio":1.0,"s_25step":42.46,"mwh_per_image":2868.32},
{"model":"efficient-large-model/sana_1600m_1024px_diffusers","hw":"a10g","s_per_step":0.1569,"fixed_s":0.759,"it_per_s":6.37,"weights_gb":3.21,"vram_gb":9.07,"vram_peak_gb":10.82,"w_mean":214.4,"w_peak":262.6,"load_s":51.4,"cfg_ratio":1.83,"s_25step":4.4,"mwh_per_image":294.2},
{"model":"stabilityai/stable-diffusion-xl-base-1.0","hw":"a10g","s_per_step":0.2888,"fixed_s":0.637,"it_per_s":3.46,"weights_gb":5.13,"vram_gb":6.95,"vram_peak_gb":11.14,"w_mean":236.6,"w_peak":272.7,"load_s":53.0,"cfg_ratio":1.74,"s_25step":7.85,"mwh_per_image":554.31},
{"model":"tongyi-mai/z-image-turbo","hw":"a10g","s_per_step":2.5343,"fixed_s":0.621,"it_per_s":0.39,"weights_gb":12.31,"vram_gb":20.53,"vram_peak_gb":23.09,"w_mean":185.7,"w_peak":200.4,"load_s":128.2,"cfg_ratio":2.08,"s_25step":63.95,"mwh_per_image":3304.4},
{"model":"arrexel/pattern-diffusion","hw":"rtxpro6000","s_per_step":0.0173,"fixed_s":0.036,"it_per_s":57.75,"weights_gb":1.73,"vram_gb":2.61,"vram_peak_gb":3.25,"w_mean":141.9,"w_peak":386.9,"load_s":2.2,"cfg_ratio":0.99,"s_25step":0.47,"mwh_per_image":18.82},
{"model":"black-forest-labs/flux.1-schnell","hw":"rtxpro6000","s_per_step":0.322,"fixed_s":0.17,"it_per_s":3.11,"weights_gb":5.95,"vram_gb":13.47,"vram_peak_gb":16.03,"w_mean":498.4,"w_peak":574.3,"load_s":8.1,"cfg_ratio":1.0,"s_25step":8.22,"mwh_per_image":1242.89},
{"model":"dream-textures/texture-diffusion","hw":"rtxpro6000","s_per_step":0.0174,"fixed_s":0.037,"it_per_s":57.47,"weights_gb":1.73,"vram_gb":2.61,"vram_peak_gb":3.25,"w_mean":150.1,"w_peak":388.9,"load_s":0.7,"cfg_ratio":1.02,"s_25step":0.47,"mwh_per_image":22.4},
{"model":"efficient-large-model/sana_1600m_1024px_diffusers","hw":"rtxpro6000","s_per_step":0.0316,"fixed_s":0.124,"it_per_s":31.65,"weights_gb":3.21,"vram_gb":9.1,"vram_peak_gb":10.85,"w_mean":282.1,"w_peak":572.6,"load_s":50.5,"cfg_ratio":1.52,"s_25step":0.91,"mwh_per_image":96.14},
{"model":"efficient-large-model/sana_600m_1024px_diffusers","hw":"rtxpro6000","s_per_step":0.0259,"fixed_s":0.128,"it_per_s":38.54,"weights_gb":1.18,"vram_gb":7.07,"vram_peak_gb":8.82,"w_mean":188.4,"w_peak":384.7,"load_s":34.6,"cfg_ratio":1.06,"s_25step":0.78,"mwh_per_image":49.59},
{"model":"idkiro/sdxs-512-dreamshaper","hw":"rtxpro6000","s_per_step":0.0078,"fixed_s":0.012,"it_per_s":127.84,"weights_gb":0.63,"vram_gb":0.92,"vram_peak_gb":1.08,"w_mean":98.0,"w_peak":232.4,"load_s":5.9,"cfg_ratio":1.01,"s_25step":0.21,"mwh_per_image":7.88}
]
Fields: s_per_step and fixed_s from a linear fit over the step sweep
at guidance 7.5; cfg_ratio is inference at guidance 7.5 over guidance
0.0 at 25 steps; mwh_per_image is mean power times duration at 25
steps, guidance 7.5.
Reproducing the run
The benchmark is a Marigold application: a models.yaml declaring the
catalogue, a marigold.toml declaring the deployment, a prompt builder
and a runner.
git clone https://github.com/bayinfosys/marigold-examples
marigold cache populate marigold-examples/benchmark-image-gen
marigold deployment start marigold-examples/benchmark-image-gen
python3 marigold-examples/benchmark-image-gen/run_benchmark.py \
--base-url http://localhost:8000 --user-id benchmark \
--out results/run1.csv
The runner reads the model list from the deployment’s catalogue, sends each parameter set to each model, polls to completion and flattens the response into a row. Sweeps and repeats live in the prompt file, and the analysis groups on the label.
The Terraform for the two instances, including the model cache volume that outlives them, is at github.com/bayinfosys/terraform-aws-marigold.