Speed: protocol and results (same harness, same GPU)
Protocol
|
|
| GPU |
1× NVIDIA H200 (143,771 MiB, driver 595.58.03, CUDA driver 13.2) (one GPU of an 8-GPU node), no other process on it |
| Host |
AMD EPYC 9554 64-core, 256 threads |
| Ines-1 |
scripts/serve_jev.py, 1 process, bf16 weights, PyTorch 2.14.0+cu130 (CUDA 13.0, cuDNN 9.24), Python 3.12.3; CUDA graphs: yes (prefill graphs for batch × length buckets ≤ 6,144 padded tokens; eager batched prefill above); no torch.compile |
| encoders (144M Julia-1 architecture, 322M laya-multilingual architecture) |
production micro-batching Jev server, 4 processes (one model copy each), bf16 autocast, PyTorch 2.13.0+cu130, Python 3.12.13; CUDA graphs: no, torch.compile: no. Checkpoints were domain fine-tunes; their speed is that of the architecture |
| load generator |
scripts/bench_jev.py: closed loop, c clients spread over 16 processes; at each level c warm-up requests, then n measured requests; HTTP/1.1 without keep-alive |
| requests |
short: 1 state of 13 words, 2 questions (choice of 3 + noul), n = 3,000 per level; typed-decisions: the 400 Spanish test cases, 5 questions each, n = 800 per level |
input length (tokens per question, from each server's usage) |
short: 61.5 (Ines-1 prompt template) / 35.0 (encoders); typed: 316.2 / 311.6 |
| runs |
two complete runs on 2026-10-01 (run 2 below; run 1 within ±10 % on throughput) |
Single request (c = 1): latency per request
| model |
short p50 / p95 |
typed case (5 questions) p50 / p95 |
| Ines-1 (1 proc.) |
9.6 / 9.7 ms |
29.6 / 38.3 ms |
| Julia-1 architecture, 144M (4 proc.) |
12.7 / 21.0 ms |
15.8 / 88.4 ms |
| laya-multilingual architecture, 322M (4 proc.) |
12.7 / 26.3 ms |
15.3 / 87.3 ms |
Maximum throughput (questions per second, best concurrency level)
| model |
short (run 2 / run 1) |
p50 / p95 at that level |
typed (run 2 / run 1) |
p50 / p95 at that level |
| Ines-1 |
1,923 / 1,883 (c=256 / 128) |
218 / 277 ms |
539 / 539 (c=32) |
294 / 377 ms |
| Julia-1 architecture |
1,694 / 1,780 (c=256) |
237 / 477 ms |
1,111 / 1,019 (c=128) |
443 / 798 ms |
| laya-multilingual architecture |
1,854 / 1,666 (c=256 / 128) |
217 / 443 ms |
763 / 835 (c=128) |
655 / 1,015 ms |
Reading
- Short requests: launch-bound. Ines-1 (one process, CUDA graphs) has the lowest and tightest single-request
latency and the same maximum throughput as the encoders within run-to-run variation (±10 %).
300-token questions: compute-bound. The encoders are faster: 1.4–2.1× the throughput and half the median
single-request latency (their p95 is higher because four processes compete for the GPU). Ines-1 reaches
~180k prompt tokens/s here, close to its isolated prefill ceiling (230k).
- Not a general speed ranking: different serving stacks (1 vs 4 processes, graphs vs none), different prompt
lengths for the same request, one GPU.
Run 3 (2026-10-06): four models, one GPU, with memory
Same load generator (scripts/bench_jev.py, closed loop, 16 client processes, HTTP/1.1 without keep-alive), same two
request sets and levels as above, one free H200 per model in turn (GPU 2 of the node, nothing else on it). The
only change to the load generator: the request's model field is taken from BENCH_MODEL (OpenJev rejects requests
without a known model; the other servers ignore it). GPU memory was sampled every 0.5 s with nvidia-smi (whole GPU).
Raw output: speed_runs/2026-10-06_part1_gemma_laya.txt, speed_runs/2026-10-06_part2_gliner_ines.txt (the first
GLiNER and Ines-1 start attempts failed on environment issues before any request and were rerun in part 2).
| model (params total / active) |
server |
short c=1 p50 / p95 |
short max q/s (c) |
typed c=1 p50 / p95 |
typed max q/s (c) |
GPU memory idle / peak |
| Ines-1 (1.59B / 405M, bf16) |
scripts/serve_jev.py, 1 process, CUDA graphs, dynamic batching |
9.4 / 9.7 ms |
1,896 (128) |
30.6 / 40.5 ms |
544 (32) |
9.7 / 21.9 GB |
| laya-multilingual arch. (322M, bf16) |
production Jev server, 4 processes, micro-batching |
13.0 / 25.9 ms |
1,848 (256) |
20.6 / 89.2 ms |
840 (128) |
8.0 / 24.1 GB |
| GLiNER2.5-multi arch. (287M) |
GLiNER Jev server, 4 workers, no batching |
48.8 / 49.3 ms |
68 (64) |
123.1 / 129.3 ms |
49 (32) |
6.7 / 26.5 GB |
| DiffusionGemma-26B-A4B-it FP8 (~26B / ~4B) |
OpenJev 0.4.0 (vLLM), max 64 sequences |
91.7 / 94.0 ms |
79 (32) |
158.8 / 170.2 ms |
143 (32) |
weights 25.8 GiB; 120.6 / 135.1 GB reserved |
Latency at the best-throughput level (p50 / p95): Ines-1 118 / 197 ms (short), 282 / 386 ms (typed); laya 212 / 483 ms,
604 / 913 ms; GLiNER 1,729 / 3,805 ms, 2,070 / 6,871 ms; Gemma 718 / 1,439 ms, 1,008 / 1,545 ms.
Reading:
- Ines-1 has the lowest single-request latency on short requests and matches the 322M encoder's peak short
throughput with one process. On ~300-token questions the encoder is still faster (840 vs 544 questions/s,
20.6 vs 30.6 ms median), but Ines-1's tail is tighter (p95 40.5 vs 89.2 ms), as in runs 1–2.
- Gemma is 5–10× slower at c=1 and ~4–24× lower in peak throughput than Ines-1 or laya, and returned HTTP 503 on
12 of the ~12,000 short requests sent at c ≥ 32 (none on typed cases). Its memory figure is vLLM's preallocation (
gpu_memory_utilization
0.80: 25.8 GiB of weights + 83 GiB of KV cache), not a minimum; it needs at least the ~26 GiB of weights.
- GLiNER's numbers measure its server, not the architecture's ceiling: that server answers one request per
worker with no batching, so throughput stays flat as concurrency rises. Input tokens per question are counted
differently by each server (
usage): Ines-1 61.5 / 316.2, laya 35.0 / 311.6, GLiNER 8.5 / 37.0, Gemma 67.0 / 136.7.
- Peak memory includes activations at the highest concurrency; idle is after load and warm-up. The encoder rows use
domain fine-tunes of those architectures (speed is the architecture's), as in runs 1–2.
- Not a general speed ranking: different serving stacks, prompt templates and process counts, one GPU.