A high-throughput and memory-efficient inference and serving engine for LLMs
Mirrored from https://github.com/tduncan-lum/Nvidia-Optimization-Stack---VLLM.git
Synced Nov 11, 05:00 UTC
[ROCm][CI][Bugfix] Multi-Modal Model Support Fixes and Attention Backend Improvements (#30270)
Signed-off-by: Andreas Karatzas <akaratza@amd.com>
Andreas Karatzas committed
Dec 18, 2025 at 20:17 UTC
7b43db210c34023cb1e8bcec1d3c49537556856f
7 files changed
+109
-47
.buildkite/test-amd.yaml
+16
-5
@@ -964,7 +964,7 @@ steps:
964
- pytest -v -s models/multimodal/processing
965
966
- label: Multi-Modal Models Test (Standard) # 60min
967
- timeout_in_minutes: 80
967
+ timeout_in_minutes: 100
968
mirror_hardwares: [amdexperimental]
969
agent_pool: mi325_1
970
# grade: Blocking
@@ -973,13 +973,15 @@ steps:
973
- vllm/
974
- tests/models/multimodal
975
commands:
976
+ - export MIOPEN_DEBUG_CONV_DIRECT=0
977
+ - export MIOPEN_DEBUG_CONV_GEMM=0
978
- pip install git+https://github.com/TIGER-AI-Lab/Mantis.git
979
- pip freeze | grep -E 'torch'
980
- pytest -v -s models/multimodal -m core_model --ignore models/multimodal/generation/test_whisper.py --ignore models/multimodal/processing
981
- cd .. && VLLM_WORKER_MULTIPROC_METHOD=spawn pytest -v -s tests/models/multimodal/generation/test_whisper.py -m core_model # Otherwise, mp_method="spawn" doesn't work
982
981
-- label: Multi-Modal Accuracy Eval (Small Models) # 150min - 180min
982
- timeout_in_minutes: 180
983
+- label: Multi-Modal Accuracy Eval (Small Models) # 5min
984
+ timeout_in_minutes: 10
985
mirror_hardwares: [amdexperimental, amdproduction]
986
agent_pool: mi325_1
987
# grade: Blocking
@@ -989,7 +991,9 @@ steps:
991
- vllm/inputs/
992
- vllm/v1/core/
993
commands:
992
- - pytest -s -v test_lm_eval_correctness.py --config-list-file=configs/models-mm-small.txt --tp-size=1
994
+ - export MIOPEN_DEBUG_CONV_DIRECT=0
995
+ - export MIOPEN_DEBUG_CONV_GEMM=0
996
+ - pytest -s -v test_lm_eval_correctness.py --config-list-file=configs/models-mm-small.txt
997
998
- label: Multi-Modal Models Test (Extended) 1 # 60min
999
timeout_in_minutes: 120
@@ -1001,10 +1005,13 @@ steps:
1005
- vllm/
1006
- tests/models/multimodal
1007
commands:
1008
+ - export MIOPEN_DEBUG_CONV_DIRECT=0
1009
+ - export MIOPEN_DEBUG_CONV_GEMM=0
1010
- pip install git+https://github.com/TIGER-AI-Lab/Mantis.git
1011
- pytest -v -s models/multimodal -m 'not core_model' --ignore models/multimodal/generation/test_common.py --ignore models/multimodal/processing
1012
1007
-- label: Multi-Modal Models Test (Extended) 2
1013
+- label: Multi-Modal Models Test (Extended) 2 #60min
1014
+ timeout_in_minutes: 120
1015
mirror_hardwares: [amdexperimental]
1016
agent_pool: mi325_1
1017
# grade: Blocking
@@ -1013,6 +1020,8 @@ steps:
1020
- vllm/
1021
- tests/models/multimodal
1022
commands:
1023
+ - export MIOPEN_DEBUG_CONV_DIRECT=0
1024
+ - export MIOPEN_DEBUG_CONV_GEMM=0
1025
- pip install git+https://github.com/TIGER-AI-Lab/Mantis.git
1026
- pytest -v -s models/multimodal/generation/test_common.py -m 'split(group=0) and not core_model'
1027
@@ -1026,6 +1035,8 @@ steps:
1035
- vllm/
1036
- tests/models/multimodal
1037
commands:
1038
+ - export MIOPEN_DEBUG_CONV_DIRECT=0
1039
+ - export MIOPEN_DEBUG_CONV_GEMM=0
1040
- pip install git+https://github.com/TIGER-AI-Lab/Mantis.git
1041
- pytest -v -s models/multimodal/generation/test_common.py -m 'split(group=1) and not core_model'
1042
tests/models/multimodal/conftest.py
renamed
+3
-6
@@ -1,6 +1,6 @@
1
# SPDX-License-Identifier: Apache-2.0
2
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
-"""Pytest configuration for vLLM tests."""
3
+"""Pytest configuration for vLLM multimodal tests."""
4
5
import warnings
6
@@ -9,16 +9,13 @@ import torch
9
from vllm.platforms import current_platform
10
11
12
-def pytest_configure(config):
13
- """Disable Flash/MemEfficient SDP on ROCm to avoid HF
14
- Transformers accuracy issues.
15
- """
12
+def pytest_collection_modifyitems(config, items):
13
+ """Configure ROCm-specific settings based on collected tests."""
14
if not current_platform.is_rocm():
15
return
16
17
skip_patterns = ["test_granite_speech.py"]
18
if any(pattern in str(arg) for arg in config.args for pattern in skip_patterns):
21
- # Skip disabling SDP for Granite Speech tests on ROCm
19
return
20
21
# Disable Flash/MemEfficient SDP on ROCm to avoid HF Transformers
tests/models/multimodal/generation/test_common.py
+30
-2
@@ -173,6 +173,13 @@ VLM_TEST_SETTINGS = {
173
auto_cls=AutoModelForImageTextToText,
174
vllm_output_post_proc=model_utils.qwen2_vllm_to_hf_output,
175
patch_hf_runner=model_utils.qwen3_vl_patch_hf_runner,
176
+ vllm_runner_kwargs={
177
+ "attention_config": {
178
+ "backend": "ROCM_AITER_FA",
179
+ },
180
+ }
181
+ if current_platform.is_rocm()
182
+ else None,
183
image_size_factors=[(0.25,), (0.25, 0.25, 0.25), (0.25, 0.2, 0.15)],
184
marks=[
185
pytest.mark.core_model,
@@ -253,8 +260,19 @@ VLM_TEST_SETTINGS = {
260
image_size_factors=[(0.25, 0.2, 0.15)],
261
vllm_runner_kwargs={
262
"model_impl": "transformers",
263
+ # TODO: [ROCm] Revert this once issue #30167 is resolved
264
+ **(
265
+ {
266
+ "mm_processor_kwargs": {
267
+ "min_pixels": 256 * 28 * 28,
268
+ "max_pixels": 1280 * 28 * 28,
269
+ },
270
+ }
271
+ if current_platform.is_rocm()
272
+ else {}
273
+ ),
274
},
257
- marks=[large_gpu_mark(min_gb=32)],
275
+ marks=[large_gpu_mark(min_gb=80 if current_platform.is_rocm() else 32)],
276
),
277
#### Extended model tests
278
"aria": VLMTestInfo(
@@ -645,7 +663,17 @@ VLM_TEST_SETTINGS = {
663
hf_output_post_proc=model_utils.minimax_vl_01_hf_output,
664
patch_hf_runner=model_utils.minimax_vl_01_patch_hf_runner,
665
auto_cls=AutoModelForImageTextToText,
648
- marks=[large_gpu_mark(min_gb=80)],
666
+ marks=[
667
+ large_gpu_mark(min_gb=80),
668
+ # TODO: [ROCm] Fix pickle issue with ROCm spawn and tp>1
669
+ pytest.mark.skipif(
670
+ current_platform.is_rocm(),
671
+ reason=(
672
+ "ROCm: Model too large for single GPU; "
673
+ "multi-GPU blocked by HF _LazyConfigMapping pickle issue with spawn"
674
+ ),
675
+ ),
676
+ ],
677
),
678
"molmo": VLMTestInfo(
679
models=["allenai/Molmo-7B-D-0924"],
tests/models/multimodal/generation/test_granite_speech.py
+1
-1
@@ -39,7 +39,7 @@ models = [MODEL_NAME]
39
def granite_speech_attention_config():
40
"""Return attention config for Granite Speech tests on ROCm."""
41
if current_platform.is_rocm():
42
- return {"backend": "TRITON_ATTN"}
42
+ return {"backend": "ROCM_AITER_FA"}
43
return None
44
45
tests/models/multimodal/pooling/conftest.py
deleted
-18
@@ -1,18 +0,0 @@
1
-# SPDX-License-Identifier: Apache-2.0
2
-# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
-"""Pytest configuration for vLLM pooling tests."""
4
-
5
-import pytest
6
-
7
-from vllm.platforms import current_platform
8
-
9
-
10
-@pytest.fixture
11
-def siglip_attention_config():
12
- """Return attention config for SigLIP tests on ROCm.
13
-
14
- On ROCm, SigLIP tests require FLEX_ATTENTION backend.
15
- """
16
- if current_platform.is_rocm():
17
- return {"backend": "FLEX_ATTENTION"}
18
- return None
vllm/model_executor/models/transformers/multimodal.py
+31
-1
@@ -22,6 +22,7 @@ from typing import TYPE_CHECKING
22
import torch
23
24
from vllm.config.utils import getattr_iter
25
+from vllm.logger import init_logger
26
from vllm.model_executor.models.interfaces import SupportsMRoPE, SupportsMultiModal
27
from vllm.model_executor.models.utils import WeightsMapper
28
from vllm.multimodal import MultiModalKwargsItems
@@ -36,6 +37,7 @@ from vllm.multimodal.inputs import (
37
from vllm.multimodal.parse import ImageProcessorItems, MultiModalDataItems
38
from vllm.multimodal.processing import BaseMultiModalProcessor, BaseProcessingInfo
39
from vllm.multimodal.profiling import BaseDummyInputsBuilder
40
+from vllm.platforms import current_platform
41
from vllm.sequence import IntermediateTensors
42
43
if TYPE_CHECKING:
@@ -52,6 +54,8 @@ DYNAMIC_ARG_DIMS = {
54
"inputs_embeds": 0,
55
}
56
57
+logger = init_logger(__name__)
58
+
59
60
class MultiModalProcessingInfo(BaseProcessingInfo):
61
def get_supported_mm_limits(self):
@@ -345,8 +349,29 @@ class MultiModalMixin(SupportsMultiModal, SupportsMRoPE):
349
350
num_image_patches = kwargs.pop("num_image_patches")
351
kwargs.pop("token_type_ids", None) # used only in `forward`
352
+
353
if pixel_values is not None:
349
- vision_embeddings = self.model.get_image_features(pixel_values, **kwargs)
354
+ # ROCm: Force math SDP backend for vision encoder to avoid accuracy issues
355
+ # with flash_sdp and mem_efficient_sdp
356
+ if current_platform.is_rocm():
357
+ # TODO: [ROCm] Fix accuracy issues with flash backend
358
+ logger.debug(
359
+ "ROCm platform detected. Forcing math SDP backend "
360
+ "for vision encoder. Currently ROCm platform has "
361
+ "accuracy issues with `flash_sdp` and"
362
+ "`mem_efficient_sdp` backends. See issue: "
363
+ "https://github.com/vllm-project/vllm/issues/30167"
364
+ )
365
+ with torch.nn.attention.sdpa_kernel(
366
+ backends=[torch.nn.attention.SDPBackend.MATH]
367
+ ):
368
+ vision_embeddings = self.model.get_image_features(
369
+ pixel_values, **kwargs
370
+ )
371
+ else:
372
+ vision_embeddings = self.model.get_image_features(
373
+ pixel_values, **kwargs
374
+ )
375
376
if isinstance(vision_embeddings, torch.Tensor):
377
if vision_embeddings.ndim == 2:
@@ -364,6 +389,11 @@ class MultiModalMixin(SupportsMultiModal, SupportsMRoPE):
389
]
390
391
return vision_embeddings
392
+ else:
393
+ logger.debug(
394
+ "No pixel values or image embeddings provided for multimodal embedding."
395
+ )
396
+ return None
397
398
def get_mrope_input_positions(
399
self,
vllm/platforms/rocm.py
+28
-14
@@ -8,6 +8,7 @@ from typing import TYPE_CHECKING, Optional
8
import torch
9
10
import vllm.envs as envs
11
+from vllm.attention.backends.abstract import AttentionType
12
from vllm.attention.backends.registry import AttentionBackendEnum
13
from vllm.logger import init_logger
14
from vllm.utils.torch_utils import cuda_device_count_stateless
@@ -204,7 +205,7 @@ class RocmPlatform(Platform):
205
assert block_size == 1, (
206
"Sparse MLA backend on ROCm only supports block size 1 for now."
207
)
207
- logger.info_once("Using Sparse MLA backend on V1 engine.")
208
+ logger.info_once("Using Sparse MLA backend.")
209
return AttentionBackendEnum.ROCM_AITER_MLA_SPARSE.get_path()
210
211
if attn_selector_config.use_mla:
@@ -239,16 +240,16 @@ class RocmPlatform(Platform):
240
return AttentionBackendEnum.FLEX_ATTENTION.get_path()
241
242
if selected_backend == AttentionBackendEnum.TRITON_ATTN:
242
- logger.info("Using Triton Attention backend on V1 engine.")
243
+ logger.info("Using Triton Attention backend.")
244
return AttentionBackendEnum.TRITON_ATTN.get_path()
245
246
if selected_backend == AttentionBackendEnum.ROCM_ATTN:
246
- logger.info("Using Rocm Attention backend on V1 engine.")
247
+ logger.info("Using Rocm Attention backend.")
248
return AttentionBackendEnum.ROCM_ATTN.get_path()
249
250
if selected_backend == AttentionBackendEnum.ROCM_AITER_FA:
251
if on_gfx9():
251
- logger.info("Using Aiter Flash Attention backend on V1 engine.")
252
+ logger.info("Using Aiter Flash Attention backend.")
253
return AttentionBackendEnum.ROCM_AITER_FA.get_path()
254
else:
255
raise ValueError(
@@ -257,25 +258,25 @@ class RocmPlatform(Platform):
258
)
259
260
if selected_backend == AttentionBackendEnum.ROCM_AITER_UNIFIED_ATTN:
260
- logger.info("Using Aiter Unified Attention backend on V1 engine.")
261
+ logger.info("Using Aiter Unified Attention backend.")
262
return AttentionBackendEnum.ROCM_AITER_UNIFIED_ATTN.get_path()
263
264
# Handle automatic backend selection based on environment variables
265
if selected_backend is None:
266
# Priority 1: Check for AITER Unified Attention (must check before MHA)
267
if envs.VLLM_ROCM_USE_AITER and envs.VLLM_ROCM_USE_AITER_UNIFIED_ATTENTION:
267
- logger.info("Using Aiter Unified Attention backend on V1 engine.")
268
+ logger.info("Using Aiter Unified Attention backend.")
269
return AttentionBackendEnum.ROCM_AITER_UNIFIED_ATTN.get_path()
270
271
# Priority 2: Check for AITER MHA (Flash Attention)
272
# Only use if explicitly enabled (not just VLLM_ROCM_USE_AITER=1)
273
if envs.VLLM_ROCM_USE_AITER and envs.VLLM_ROCM_USE_AITER_MHA and on_gfx9():
273
- logger.info("Using Aiter Flash Attention backend on V1 engine.")
274
+ logger.info("Using Aiter Flash Attention backend.")
275
return AttentionBackendEnum.ROCM_AITER_FA.get_path()
276
277
# Priority 3: Check for ROCM_ATTN (prefill-decode split)
278
if envs.VLLM_V1_USE_PREFILL_DECODE_ATTENTION:
278
- logger.info("Using Rocm Attention backend on V1 engine.")
279
+ logger.info("Using Rocm Attention backend.")
280
return AttentionBackendEnum.ROCM_ATTN.get_path()
281
282
# Priority 4: Check for AITER enabled without specific flags
@@ -285,11 +286,19 @@ class RocmPlatform(Platform):
286
and on_gfx9()
287
and envs.VLLM_ROCM_USE_AITER_MHA is not False
288
):
288
- logger.info("Using Aiter Flash Attention backend on V1 engine.")
289
+ logger.info("Using Aiter Flash Attention backend.")
290
return AttentionBackendEnum.ROCM_AITER_FA.get_path()
291
292
+ # Priority 5: If model is Encoder-only self-attention type
293
+ if (
294
+ attn_selector_config.attn_type is not None
295
+ and attn_selector_config.attn_type == AttentionType.ENCODER_ONLY
296
+ ):
297
+ logger.info("Using FlexAttention backend.")
298
+ return AttentionBackendEnum.FLEX_ATTENTION.get_path()
299
+
300
# Default: Triton Unified Attention
292
- logger.info("Using Triton Attention backend on V1 engine.")
301
+ logger.info("Using Triton Attention backend.")
302
return AttentionBackendEnum.TRITON_ATTN.get_path()
303
304
raise RuntimeError(
@@ -324,14 +333,19 @@ class RocmPlatform(Platform):
333
334
from vllm._aiter_ops import rocm_aiter_ops
335
327
- if rocm_aiter_ops.is_mha_enabled():
328
- # Note: AITER FA is only supported for Qwen-VL models.
329
- # TODO: Add support for other VL models in their model class.
336
+ if rocm_aiter_ops.is_enabled():
337
+ logger.info_once("Using AITER Flash Attention backend for ViT model.")
338
return AttentionBackendEnum.ROCM_AITER_FA
339
332
- if on_gfx9() and find_spec("flash_attn") is not None:
340
+ if (
341
+ on_gfx9()
342
+ and find_spec("flash_attn") is not None
343
+ and (dtype == torch.float16 or dtype == torch.bfloat16)
344
+ ):
345
+ logger.info_once("Using Flash Attention backend for ViT model.")
346
return AttentionBackendEnum.FLASH_ATTN
347
348
+ logger.info_once("Using Torch SDPA backend for ViT model.")
349
return AttentionBackendEnum.TORCH_SDPA
350
351
@classmethod