In T412338, we implemented the embeddings model-server using the HuggingFace Transformers inference backend with CK FlashAttention. As we work towards standardizing our LLM serving backend (T385173, T415627), we are migrating this service to use vLLM with AITER, which will improve throughput and memory efficiency (via PagedAttention).
Description
Details
- Other Assignee
- OKarakaya-WMF
| Status | Subtype | Assigned | Task | ||
|---|---|---|---|---|---|
| Resolved | OKarakaya-WMF | T412338 Q2 FY2025-26 Goal: Semantic Search - Embeddings Service for MVP | |||
| Resolved | kevinbazira | T418976 Migrate embeddings inference service from HF Transformers+CK FlashAttention to vLLM+AITER | |||
| Resolved | kevinbazira | T419650 Add ROCm build dependencies to wmf-debian-vllm image to support AITER kernel compilation |
Event Timeline
The embeddings model-server's inference backend has been migrated from transformers+fa2 to vLLM 0.14. I've tested the new model-server on ml-lab, and it was able to load the Qwen3-Embedding-0.6B model using vLLM on an MI210 GPU and generate embeddings as shown below:
1.Run the model-server
$ docker run --network=host -it \ --user root \ --device=/dev/kfd --device=/dev/dri \ --group-add=$(getent group video | cut -d: -f3) \ --group-add=$(getent group render | cut -d: -f3) \ --ipc=host \ --security-opt seccomp=unconfined \ --shm-size 16g \ -v /home/kevinbazira/test_embeddings/qwen3-embedding-model:/mnt/models \ docker-registry.wikimedia.org/wikimedia/machinelearning-liftwing-inference-services-embeddings:2026-03-04-145043-publish
It should start the inference-service as shown in:
2.Query the inference service
$ time curl -s localhost:8080/v1/models/qwen3-embedding:predict -X POST -d '{"input": ["text1", "text2"]}' -i -H "Content-type: application/json" HTTP/1.1 200 OK date: Wed, 04 Mar 2026 15:26:03 GMT server: uvicorn content-length: 43502 content-type: application/json { "object":"list", "data":[ { "object":"embedding", "embedding":[-0.036402568221092224, ...], "index":0 }, { "object":"embedding", "embedding":[-0.025051085278391838, ...], "index":1 } ], "model":"qwen3-embedding" } real 0m0.789s user 0m0.005s sys 0m0.009s
Change #1248310 had a related patch set uploaded (by Kevin Bazira; author: Kevin Bazira):
[operations/deployment-charts@master] ml-services: update embeddings isvc image
Change #1248310 merged by jenkins-bot:
[operations/deployment-charts@master] ml-services: update embeddings isvc image
The new embeddings model-server that uses vLLM as the inference backend instead of transformers+fa2 has been deployed in LiftWing prod on an MI300x GPU:
$ time curl "https://inference.svc.eqiad.wmnet:30443/v1/models/qwen3-embedding:predict" -X POST -d '{"input": ["text1", "text2"]}' -H "Host: embeddings.llm.wikimedia.org" -H "Content-Type: application/json" --http1.1 { "object":"list", "data":[ { "object":"embedding", "embedding":[-0.03630506619811058, ...], "index":0 }, { "object":"embedding", "embedding":[-0.02502359449863434, ...], "index":1 } ], "model":"Qwen3-Embedding-0.6B" } real 0m0.482s user 0m0.016s sys 0m0.003s
transformer test1 (light):
(venv) ozge@stat1010:~/repos/wiki/gerrit/inference-services/test/locust$ MODEL=embeddings locust
Min length: 50, Max length: 350
question_length
count 3952.000000
mean 84.550354
std 37.088196
min 50.000000
25% 64.000000
50% 77.000000
75% 93.000000
max 348.000000
Prompt length: 108
[2026-01-08 12:50:39,141] stat1010/INFO/locust.main: Run time limit set to 120 seconds
[2026-01-08 12:50:39,142] stat1010/INFO/locust.main: Starting Locust 2.31.5
[2026-01-08 12:50:39,142] stat1010/INFO/locust.runners: Ramping to 2 users at a rate of 10.00 per second
[2026-01-08 12:50:39,143] stat1010/INFO/locust.runners: All users spawned: {"Embeddings": 2} (2 total users)
[2026-01-08 12:52:38,649] stat1010/INFO/locust.main: --run-time limit reached, shutting down
Load test results are within the threshold
[2026-01-08 12:52:38,727] stat1010/INFO/locust.main: Shutting down (exit code 0)
Type Name # reqs # fails | Avg Min Max Med | req/s failures/s
--------|----------------------------------------------------------------------------|-------|-------------|-------|-------|-------|-------|--------|-----------
POST /v1/models/qwen3-embedding:predict 2586 0(0.00%) | 41 28 292 34 | 21.64 0.00
--------|----------------------------------------------------------------------------|-------|-------------|-------|-------|-------|-------|--------|-----------
Aggregated 2586 0(0.00%) | 41 28 292 34 | 21.64 0.00
Response time percentiles (approximated)
Type Name 50% 66% 75% 80% 90% 95% 98% 99% 99.9% 99.99% 100% # reqs
--------|--------------------------------------------------------------------------------|--------|------|------|------|------|------|------|------|------|------|------|------
POST /v1/models/qwen3-embedding:predict 34 38 45 48 56 61 81 260 280 290 290 2586
--------|--------------------------------------------------------------------------------|--------|------|------|------|------|------|------|------|------|------|------|------
Aggregatedvllm test1 (light):
(venv) ozge@stat1010:~/repos/wiki/gerrit/inference-services/test/locust$ MODEL=embeddings locust --host https://inference.svc.eqiad.wmnet:30443
Min length: 50, Max length: 350
question_length
count 3952.000000
mean 84.550354
std 37.088196
min 50.000000
25% 64.000000
50% 77.000000
75% 93.000000
max 348.000000
Prompt length: 108
[2026-03-05 08:41:19,403] stat1010/INFO/locust.main: Run time limit set to 120 seconds
[2026-03-05 08:41:19,403] stat1010/INFO/locust.main: Starting Locust 2.31.5
[2026-03-05 08:41:19,403] stat1010/INFO/locust.runners: Ramping to 2 users at a rate of 10.00 per second
[2026-03-05 08:41:19,404] stat1010/INFO/locust.runners: All users spawned: {"Embeddings": 2} (2 total users)
[2026-03-05 08:43:18,886] stat1010/INFO/locust.main: --run-time limit reached, shutting down
Load test results are within the threshold
[2026-03-05 08:43:18,973] stat1010/INFO/locust.main: Shutting down (exit code 0)
Type Name # reqs # fails | Avg Min Max Med | req/s failures/s
--------|----------------------------------------------------------------------------|-------|-------------|-------|-------|-------|-------|--------|-----------
POST /v1/models/qwen3-embedding:predict 3454 0(0.00%) | 18 12 757 15 | 28.89 0.00
--------|----------------------------------------------------------------------------|-------|-------------|-------|-------|-------|-------|--------|-----------
Aggregated 3454 0(0.00%) | 18 12 757 15 | 28.89 0.00
Response time percentiles (approximated)
Type Name 50% 66% 75% 80% 90% 95% 98% 99% 99.9% 99.99% 100% # reqs
--------|--------------------------------------------------------------------------------|--------|------|------|------|------|------|------|------|------|------|------|------
POST /v1/models/qwen3-embedding:predict 15 16 17 17 21 24 26 31 240 760 760 3454
--------|--------------------------------------------------------------------------------|--------|------|------|------|------|------|------|------|------|------|------|------
Aggregated 15 16 17 17 21 24 26 31 240 760 760 3454transformer test2 (heavy):
vllm test2 (heavy):
(venv) ozge@stat1010:~/repos/wiki/gerrit/inference-services/test/locust$ MODEL=embeddings locust --host https://inference.svc.eqiad.wmnet:30443 --users 10 --run-time 4m
Min length: 10, Max length: 350
question_length
count 4610.000000
mean 78.490456
std 37.470874
min 20.000000
25% 58.000000
50% 73.000000
75% 90.000000
max 348.000000
Prompt length: 108
[2026-03-05 08:44:37,699] stat1010/INFO/locust.main: Run time limit set to 240 seconds
[2026-03-05 08:44:37,699] stat1010/INFO/locust.main: Starting Locust 2.31.5
[2026-03-05 08:44:37,700] stat1010/INFO/locust.runners: Ramping to 10 users at a rate of 10.00 per second
[2026-03-05 08:44:37,700] stat1010/INFO/locust.runners: All users spawned: {"Embeddings": 10} (10 total users)
[2026-03-05 08:48:37,193] stat1010/INFO/locust.main: --run-time limit reached, shutting down
Load test results are within the threshold
[2026-03-05 08:48:37,292] stat1010/INFO/locust.main: Shutting down (exit code 1)
Type Name # reqs # fails | Avg Min Max Med | req/s failures/s
--------|----------------------------------------------------------------------------|-------|-------------|-------|-------|-------|-------|--------|-----------
POST /v1/models/qwen3-embedding:predict 22610 1(0.00%) | 54 12 573 52 | 94.38 0.00
--------|----------------------------------------------------------------------------|-------|-------------|-------|-------|-------|-------|--------|-----------
Aggregated 22610 1(0.00%) | 54 12 573 52 | 94.38 0.00
Response time percentiles (approximated)
Type Name 50% 66% 75% 80% 90% 95% 98% 99% 99.9% 99.99% 100% # reqs
--------|--------------------------------------------------------------------------------|--------|------|------|------|------|------|------|------|------|------|------|------
POST /v1/models/qwen3-embedding:predict 52 58 62 64 71 77 88 250 320 340 570 22610
--------|--------------------------------------------------------------------------------|--------|------|------|------|------|------|------|------|------|------|------|------
Aggregated 52 58 62 64 71 77 88 250 320 340 570 22610
Error report
# occurrences Error
------------------|---------------------------------------------------------------------------------------------------------------------------------------------
1 POST /v1/models/qwen3-embedding:predict: BadStatusCode('https://inference.svc.eqiad.wmnet:30443/v1/models/qwen3-embedding:predict', code=502)
------------------|---------------------------------------------------------------------------------------------------------------------------------------------- Overall, number of requests per second increased by 3X, and median latency decreased by 4.5X
Change #1248416 had a related patch set uploaded (by Kevin Bazira; author: Kevin Bazira):
[operations/deployment-charts@master] ml-services: add performance optimization env vars to embeddings isvc
Change #1248416 merged by jenkins-bot:
[operations/deployment-charts@master] ml-services: add performance optimization env vars to embeddings isvc
Change #1248457 had a related patch set uploaded (by Kevin Bazira; author: Kevin Bazira):
[machinelearning/liftwing/inference-services@main] embeddings: install ROCm device libs to fix runtime compilation failure
Change #1248457 merged by jenkins-bot:
[machinelearning/liftwing/inference-services@main] embeddings: install ROCm device libs to fix runtime compilation failure
Change #1248462 had a related patch set uploaded (by Kevin Bazira; author: Kevin Bazira):
[operations/deployment-charts@master] ml-services: update embeddings isvc to image that includes GPU device bitcode files
Change #1248462 merged by jenkins-bot:
[operations/deployment-charts@master] ml-services: update embeddings isvc to image that includes GPU device bitcode files
Change #1248475 had a related patch set uploaded (by Kevin Bazira; author: Kevin Bazira):
[machinelearning/liftwing/inference-services@main] embeddings: install ROCm libs to add missing dev headers required by AITER
Change #1248475 merged by jenkins-bot:
[machinelearning/liftwing/inference-services@main] embeddings: install ROCm libs to add missing dev headers required by AITER
Change #1248480 had a related patch set uploaded (by Kevin Bazira; author: Kevin Bazira):
[operations/deployment-charts@master] ml-services: update embeddings isvc to image that adds missing dev headers required by AITER
Change #1248480 merged by jenkins-bot:
[operations/deployment-charts@master] ml-services: update embeddings isvc to image that adds missing dev headers required by AITER
Change #1248522 had a related patch set uploaded (by Kevin Bazira; author: Kevin Bazira):
[operations/deployment-charts@master] ml-services: increase memory in embeddings isvc to fix OOM issue caused AITER
Change #1248522 merged by jenkins-bot:
[operations/deployment-charts@master] ml-services: increase memory in embeddings isvc to fix OOM issue caused AITER
Change #1248531 had a related patch set uploaded (by Kevin Bazira; author: Kevin Bazira):
[operations/deployment-charts@master] ml-services: bump llm limitranges to enable embeddings isvc deployment
Change #1248531 merged by jenkins-bot:
[operations/deployment-charts@master] ml-services: bump llm limitranges to enable embeddings isvc deployment
Change #1248855 had a related patch set uploaded (by Kevin Bazira; author: Kevin Bazira):
[operations/deployment-charts@master] ml-services: revert embeddings isvc image to one that doesn't use AITER
Change #1248855 merged by jenkins-bot:
[operations/deployment-charts@master] ml-services: revert embeddings isvc image to one that doesn't use AITER
Change #1248859 had a related patch set uploaded (by Kevin Bazira; author: Kevin Bazira):
[operations/deployment-charts@master] ml-services: rollback embeddings isvc image
Change #1248859 merged by jenkins-bot:
[operations/deployment-charts@master] ml-services: rollback embeddings isvc image
Change #1249081 had a related patch set uploaded (by Kevin Bazira; author: Kevin Bazira):
[operations/deployment-charts@master] ml-services: add embeddings-staging isvc
Change #1249081 merged by jenkins-bot:
[operations/deployment-charts@master] ml-services: add embeddings-staging isvc
Change #1249204 had a related patch set uploaded (by Kevin Bazira; author: Kevin Bazira):
[operations/deployment-charts@master] ml-services: remove unused env vars in embeddings-staging isvc
Change #1249204 merged by jenkins-bot:
[operations/deployment-charts@master] ml-services: remove unused env vars in embeddings-staging isvc
Change #1249209 had a related patch set uploaded (by Kevin Bazira; author: Kevin Bazira):
[operations/deployment-charts@master] ml-services: add MAX_MODEL_LEN performance optimization env var to embeddings-staging isvc
Change #1249209 merged by jenkins-bot:
[operations/deployment-charts@master] ml-services: add MAX_MODEL_LEN performance optimization env var to embeddings-staging isvc
Change #1249213 had a related patch set uploaded (by Kevin Bazira; author: Kevin Bazira):
[operations/deployment-charts@master] ml-services: add MAX_NUM_BATCHED_TOKENS performance optimization env var to embeddings-staging isvc
Change #1249213 merged by jenkins-bot:
[operations/deployment-charts@master] ml-services: add MAX_NUM_BATCHED_TOKENS performance optimization env var to embeddings-staging isvc
Change #1249255 had a related patch set uploaded (by Kevin Bazira; author: Kevin Bazira):
[operations/deployment-charts@master] ml-services: add VLLM_ROCM_USE_AITER performance optimization env var to embeddings-staging isvc
Change #1249255 merged by jenkins-bot:
[operations/deployment-charts@master] ml-services: add VLLM_ROCM_USE_AITER performance optimization env var to embeddings-staging isvc
Change #1249326 had a related patch set uploaded (by Kevin Bazira; author: Kevin Bazira):
[machinelearning/liftwing/inference-services@main] embeddings: install the hipBLASLt development headers
Change #1249326 merged by jenkins-bot:
[machinelearning/liftwing/inference-services@main] embeddings: install the hipBLASLt development headers
Change #1249333 had a related patch set uploaded (by Kevin Bazira; author: Kevin Bazira):
[operations/deployment-charts@master] ml-services: update embeddings-staging image to one that installs the hipblaslt-dev headers
Change #1249333 merged by jenkins-bot:
[operations/deployment-charts@master] ml-services: update embeddings-staging image to one that installs the hipblaslt-dev headers
Change #1249338 had a related patch set uploaded (by Kevin Bazira; author: Kevin Bazira):
[machinelearning/liftwing/inference-services@main] embeddings: install hipsolver-dev package
Change #1249338 merged by jenkins-bot:
[machinelearning/liftwing/inference-services@main] embeddings: install hipsolver-dev package
Change #1249345 had a related patch set uploaded (by Kevin Bazira; author: Kevin Bazira):
[operations/deployment-charts@master] ml-services: update embeddings-staging image to one that installs the hipsolver-dev headers
Change #1249345 merged by jenkins-bot:
[operations/deployment-charts@master] ml-services: update embeddings-staging image to one that installs the hipsolver-dev headers
vLLM uses Triton FlashAttention as the default attention backend. AMD released the AI Tensor Engine for ROCm (AITER), and vLLM now recommends using AITER as it's a more performant backend for MI300x GPUs. Based on this recommendation, we enabled AITER in the embeddings model-server.
On top of AITER, below are all the optimizations we have implemented:
- VLLM_ROCM_USE_AITER: Enabled ROCm's AI Tensor Engine for MI300x specific matrix core optimizations.
- VLLM_USE_TRITON_FLASH_ATTN: Disabled Triton for Attention in favor of AITER.
- MAX_JOBS: Restricted the ninja build system to a single compilation thread. JIT-compiling the AITER kernels is memory-intensive, and multiple concurrent jobs can exceed the k8s pod's 16Gi RAM limit and trigger an OOM kill during the initial build.
- MAX_MODEL_LEN: Matched Qwen3 sequence length limit to enable the search team to index entire articles without losing semantic information at the end of the document. We can always cap it at 8192, but any text beyond that point gets truncated (ignored) by the embedding model.
- MAX_NUM_BATCHED_TOKENS: Matched the MAX_MODEL_LEN to ensure the engine can process at least one full-length article in a single pass, or efficiently pack hundreds of shorter search queries together. Leaving it at a lower default would bottleneck throughput and prevent us from utilizing the full 32K context in one go.
- TRUST_REMOTE_CODE: Disabled in production since we store this model in Swift and prod doesn't need to access HuggingFace.
The embeddings-staging isvc starts in the pod on eqiad as shown below:
Querying the embeddings-staging isvc returns:
$ time curl "https://inference.svc.eqiad.wmnet:30443/v1/models/qwen3-embedding-staging:predict" -X POST -d '{"input": ["text1", "text2"]}' -H "Host: embeddings-staging.llm.wikimedia.org" -H "Content-Type: application/json" --http1.1 { "object":"list", "data":[ { "object":"embedding", "embedding":[-0.03621598333120346, ...], "index":0 }, { "object":"embedding","embedding":[-0.02509966306388378, ...], "index":1 } ], "model":"Qwen3-Embedding-0.6B" } real 0m0.200s user 0m0.017s sys 0m0.004s
after the aiter changes.
reference to compare is vllm test2 (heavy):
(venv) ozge@stat1010:~/repos/wiki/gerrit/inference-services/test/locust$ MODEL=embeddings locust --host https://inference.svc.eqiad.wmnet:30443 --users 10 --run-time 4m
Min length: 10, Max length: 350
question_length
count 4610.000000
mean 78.490456
std 37.470874
min 20.000000
25% 58.000000
50% 73.000000
75% 90.000000
max 348.000000
Prompt length: 108
[2026-03-11 12:55:34,104] stat1010/INFO/locust.main: Run time limit set to 240 seconds
[2026-03-11 12:55:34,104] stat1010/INFO/locust.main: Starting Locust 2.31.5
[2026-03-11 12:55:34,104] stat1010/INFO/locust.runners: Ramping to 10 users at a rate of 10.00 per second
[2026-03-11 12:55:34,105] stat1010/INFO/locust.runners: All users spawned: {"Embeddings": 10} (10 total users)
[2026-03-11 12:59:33,599] stat1010/INFO/locust.main: --run-time limit reached, shutting down
Load test results are within the threshold
[2026-03-11 12:59:33,689] stat1010/INFO/locust.main: Shutting down (exit code 0)
Type Name # reqs # fails | Avg Min Max Med | req/s failures/s
--------|----------------------------------------------------------------------------|-------|-------------|-------|-------|-------|-------|--------|-----------
POST /v1/models/qwen3-embedding:predict 23277 0(0.00%) | 51 11 651 51 | 97.17 0.00
--------|----------------------------------------------------------------------------|-------|-------------|-------|-------|-------|-------|--------|-----------
Aggregated 23277 0(0.00%) | 51 11 651 51 | 97.17 0.00
Response time percentiles (approximated)
Type Name 50% 66% 75% 80% 90% 95% 98% 99% 99.9% 99.99% 100% # reqs
--------|--------------------------------------------------------------------------------|--------|------|------|------|------|------|------|------|------|------|------|------
POST /v1/models/qwen3-embedding:predict 51 56 60 62 68 73 80 86 290 620 650 23277
--------|--------------------------------------------------------------------------------|--------|------|------|------|------|------|------|------|------|------|------|------
Aggregated 51 56 60 62 68 73 80 86 290 620 650 23277after aiter changes on staging:
(venv) ozge@stat1010:~/repos/wiki/gerrit/inference-services/test/locust$ MODEL=embeddings locust --host https://inference.svc.eqiad.wmnet:30443 --users 10 --run-time 4m
Min length: 10, Max length: 350
question_length
count 4610.000000
mean 78.490456
std 37.470874
min 20.000000
25% 58.000000
50% 73.000000
75% 90.000000
max 348.000000
Prompt length: 108
[2026-03-12 17:09:49,113] stat1010/INFO/locust.main: Run time limit set to 240 seconds
[2026-03-12 17:09:49,113] stat1010/INFO/locust.main: Starting Locust 2.31.5
[2026-03-12 17:09:49,114] stat1010/INFO/locust.runners: Ramping to 10 users at a rate of 10.00 per second
[2026-03-12 17:09:49,114] stat1010/INFO/locust.runners: All users spawned: {"Embeddings": 10} (10 total users)
[2026-03-12 17:13:47,638] stat1010/INFO/locust.main: --run-time limit reached, shutting down
Load test results are within the threshold
[2026-03-12 17:13:47,741] stat1010/INFO/locust.main: Shutting down (exit code 0)
Type Name # reqs # fails | Avg Min Max Med | req/s failures/s
--------|----------------------------------------------------------------------------|-------|-------------|-------|-------|-------|-------|--------|-----------
POST /v1/models/qwen3-embedding-staging:predict 23598 0(0.00%) | 49 12 894 48 | 98.90 0.00
--------|----------------------------------------------------------------------------|-------|-------------|-------|-------|-------|-------|--------|-----------
Aggregated 23598 0(0.00%) | 49 12 894 48 | 98.90 0.00
Response time percentiles (approximated)
Type Name 50% 66% 75% 80% 90% 95% 98% 99% 99.9% 99.99% 100% # reqs
--------|--------------------------------------------------------------------------------|--------|------|------|------|------|------|------|------|------|------|------|------
POST /v1/models/qwen3-embedding-staging:predict 48 54 57 59 65 70 77 84 300 340 890 23598
--------|--------------------------------------------------------------------------------|--------|------|------|------|------|------|------|------|------|------|------|------
Aggregated 48 54 57 59 65 70 77 84 300 340 890 23598Thank you for running the load tests @OKarakaya-WMF. Below is a consolidated report of the optimizations we have implemented and their corresponding performance results for the embeddings isvc that is running on an MI300x GPU:
| Inference Backend | Requests/s (Throughput) | Median Latency | p90 | Failure Rate | Total Requests | Report | Status |
|---|---|---|---|---|---|---|---|
| HF Transformers+CK FlashAttention (T412338#11498835) | 33.94 | 240ms | 280ms | 0.06% | 8130 | T418976#11676658 | Stable. Was previously deployed in LiftWing prod and used for semantic search experiments. |
| vLLM+Triton FlashAttention (T418976#11676540) | 94.38 | 52ms | 71ms | 0.00% | 22610 | T418976#11676658 | Stable. Is currently deployed in LiftWing prod and used in semantic search prod. |
| vLLM+AITER (T418976#11690847) | 98.90 | 48ms | 65ms | 0.00% | 23598 | T418976#11676658 | Still under evaluation. We have experienced a couple of issues with: JIT compilation of the AITER kernels (P89805) and V1 engine prefix caching (P89849). Although these issues have been resolved, we'll continue monitoring this optimization to confirm it's stable before deploying it to LiftWing prod. |
