Skip to content

Commit 4311dd4

Browse files
committed
test(megatron): make VLM distributed tests NPU-compatible
After main split the integration tests into ``tests/test_megatron_engine_vlm_distributed.py`` and renamed the torchrun script to ``run_megatron_engine_vlm_distributed.py`` (areal-project#1301), re-apply the same NPU compatibility shims as the previous combined-file version: - ``try: import mindspeed.megatron_adaptor`` at the top of both files so MindSpeed's adapters land before mbridge transitive imports on NPU. - Replace ``CUDA_AVAILABLE`` with ``ACCELERATOR_AVAILABLE`` driven by ``current_platform.device_type in ("cuda", "npu")`` and update the five ``@pytest.mark.skipif`` decorators / two ``device_count()`` checks. - ``current_platform.synchronize()`` instead of ``torch.cuda.synchronize()`` in the torchrun cleanup path. The model path is already centralized in ``areal/utils/testing_utils.py::DENSE_MODEL_PATHS`` (env override via ``VLM_MODEL_PATH``), so no additional path resolution is needed here.
1 parent 7d43910 commit 4311dd4

2 files changed

Lines changed: 26 additions & 14 deletions

File tree

tests/test_megatron_engine_vlm_distributed.py

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,14 @@
1717
import sys
1818

1919
import pytest
20-
import torch
20+
21+
try:
22+
import mindspeed.megatron_adaptor # noqa: F401 isort: skip # must precede mbridge on NPU
23+
except ImportError:
24+
pass
2125

2226
from areal.api.alloc_mode import ModelAllocation
27+
from areal.infra.platforms import current_platform
2328
from areal.utils.network import find_free_ports
2429
from areal.utils.testing_utils import DENSE_MODEL_PATHS, MOE_MODEL_PATHS
2530

@@ -29,7 +34,8 @@
2934
/ "run_megatron_engine_vlm_distributed.py"
3035
).resolve()
3136

32-
CUDA_AVAILABLE = torch.cuda.is_available()
37+
# Detect any accelerator (CUDA or NPU)
38+
ACCELERATOR_AVAILABLE = current_platform.device_type in ("cuda", "npu")
3339

3440

3541
def _run_vlm_test(
@@ -122,7 +128,7 @@ def _run_vlm_test(
122128
{"VLM_MODEL_PATH": MOE_MODEL_PATHS["qwen3_vl_moe"]},
123129
id="qwen3_vl_moe",
124130
marks=pytest.mark.skipif(
125-
torch.cuda.device_count() < 8,
131+
current_platform.device_count() < 8,
126132
reason="Qwen3-VL-MoE-30B-A3B requires at least 8 GPUs",
127133
),
128134
),
@@ -131,7 +137,7 @@ def _run_vlm_test(
131137

132138
@pytest.mark.gpu
133139
@pytest.mark.slow
134-
@pytest.mark.skipif(not CUDA_AVAILABLE, reason="CUDA not available")
140+
@pytest.mark.skipif(not ACCELERATOR_AVAILABLE, reason="No accelerator available")
135141
@pytest.mark.parametrize("model_env", _VLM_MODELS)
136142
def test_engine_initializes(model_env, tmp_path_factory):
137143
"""Verify VLM engine detects vision model and loads processor."""
@@ -141,7 +147,7 @@ def test_engine_initializes(model_env, tmp_path_factory):
141147

142148
@pytest.mark.gpu
143149
@pytest.mark.slow
144-
@pytest.mark.skipif(not CUDA_AVAILABLE, reason="CUDA not available")
150+
@pytest.mark.skipif(not ACCELERATOR_AVAILABLE, reason="No accelerator available")
145151
@pytest.mark.parametrize("model_env", _VLM_MODELS)
146152
def test_simple_forward(model_env, tmp_path_factory):
147153
"""Verify forward pass with VLM inputs completes."""
@@ -151,7 +157,7 @@ def test_simple_forward(model_env, tmp_path_factory):
151157

152158
@pytest.mark.gpu
153159
@pytest.mark.slow
154-
@pytest.mark.skipif(not CUDA_AVAILABLE, reason="CUDA not available")
160+
@pytest.mark.skipif(not ACCELERATOR_AVAILABLE, reason="No accelerator available")
155161
@pytest.mark.parametrize("model_env", _VLM_MODELS)
156162
def test_hf_save_load_weights(model_env, tmp_path_factory):
157163
"""Verify save/load preserves VLM weights and saves processor."""
@@ -168,11 +174,11 @@ def test_hf_save_load_weights(model_env, tmp_path_factory):
168174
@pytest.mark.gpu
169175
@pytest.mark.multi_gpu
170176
@pytest.mark.slow
171-
@pytest.mark.skipif(not CUDA_AVAILABLE, reason="CUDA not available")
177+
@pytest.mark.skipif(not ACCELERATOR_AVAILABLE, reason="No accelerator available")
172178
@pytest.mark.parametrize("model_env", _VLM_MODELS)
173179
def test_train_tensor_parallel(model_env, tmp_path_factory):
174180
"""VLM training with TP=2 to avoid single-device OOM."""
175-
if torch.cuda.device_count() < 2:
181+
if current_platform.device_count() < 2:
176182
pytest.skip("VLM TP training requires at least 2 GPUs")
177183
output = str(tmp_path_factory.mktemp("vlm_test") / "train_tp2.out")
178184
_run_vlm_test(
@@ -191,7 +197,7 @@ def test_train_tensor_parallel(model_env, tmp_path_factory):
191197

192198
@pytest.mark.multi_gpu
193199
@pytest.mark.slow
194-
@pytest.mark.skipif(not CUDA_AVAILABLE, reason="CUDA not available")
200+
@pytest.mark.skipif(not ACCELERATOR_AVAILABLE, reason="No accelerator available")
195201
def test_qwen3vl_moe_expert_parallel(tmp_path_factory):
196202
"""Forward smoke test for Qwen3-VL-MoE under ``(attn:d2t4|ffn:d2e4)``.
197203
@@ -200,7 +206,7 @@ def test_qwen3vl_moe_expert_parallel(tmp_path_factory):
200206
``InvalidAllocationModeError`` (attn=4 vs ffn=8). Validates the hybrid
201207
attn/ffn parser, EP-aware weight init, and VLM forward path.
202208
"""
203-
if torch.cuda.device_count() < 8:
209+
if current_platform.device_count() < 8:
204210
pytest.skip("Qwen3-VL-MoE expert parallel requires 8 GPUs to run")
205211
output = str(
206212
tmp_path_factory.mktemp("test_output") / "qwen3vl_moe_expert_parallel.out"
@@ -215,15 +221,15 @@ def test_qwen3vl_moe_expert_parallel(tmp_path_factory):
215221

216222
@pytest.mark.multi_gpu
217223
@pytest.mark.slow
218-
@pytest.mark.skipif(not CUDA_AVAILABLE, reason="CUDA not available")
224+
@pytest.mark.skipif(not ACCELERATOR_AVAILABLE, reason="No accelerator available")
219225
def test_qwen3vl_moe_dcp_save_load(tmp_path_factory):
220226
"""DCP save/load round-trip for Qwen3-VL-MoE under ``(attn:d2p1t4|ffn:d1p1t2e4)``.
221227
222228
Allocation: attn DP=2 PP=1 TP=4 (8 GPUs); ffn DP=1 PP=1 TP=2 EP=4 (8 GPUs).
223229
Drops the ``cp=2`` segment from the dense Qwen3-MoE analog because VLM
224230
forbids CP>1 (megatron_engine.py:347).
225231
"""
226-
if torch.cuda.device_count() < 8:
232+
if current_platform.device_count() < 8:
227233
pytest.skip("Qwen3-VL-MoE DCP save load requires 8 GPUs to run")
228234
output = str(tmp_path_factory.mktemp("test_output") / "qwen3vl_moe_save_load.out")
229235
_run_vlm_test(

tests/torchrun/run_megatron_engine_vlm_distributed.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,12 @@
1919
from pathlib import Path
2020
from typing import Any
2121

22-
import torch
22+
try:
23+
import mindspeed.megatron_adaptor # noqa: F401 # must precede mbridge on NPU
24+
except ImportError:
25+
pass
26+
27+
import torch # noqa: I001
2328
import torch.distributed as dist
2429

2530
from areal.api import FinetuneSpec, SaveLoadMeta
@@ -31,6 +36,7 @@
3136
TrainEngineConfig,
3237
)
3338
from areal.engine import MegatronEngine
39+
from areal.infra.platforms import current_platform
3440
from areal.utils.data import broadcast_tensor_container
3541
from areal.utils.testing_utils import DENSE_MODEL_PATHS
3642

@@ -135,7 +141,7 @@ def _make_input(engine: MegatronEngine) -> dict[str, Any]:
135141

136142

137143
def _cleanup(engine: MegatronEngine):
138-
torch.cuda.synchronize()
144+
current_platform.synchronize()
139145
dist.barrier()
140146
engine.destroy()
141147

0 commit comments

Comments
 (0)