Skip to content

Commit ccc21b4

Browse files
noemotiovonFightingZhenlowdy1
committed
feat: add device abstraction and Ascend NPU support
This commit introduces native support for Ascend NPUs in the ROLL project while maintaining compatibility with existing CUDA-based infrastructure. Key changes include: - Added a unified device abstraction interface for initialization, memory management, and synchronization, enabling extensibility for both CUDA and Ascend. - Replaced direct usage of Ray CUDA resource APIs with the new abstraction layer to support heterogeneous multi-device environments. - Integrated Ascend inference backend via vLLM + vLLM-Ascend. - Added experimental training support with DeepSpeed on Ascend hardware. - Added documentation for Ascend usage. This enhancement lays the foundation for seamless switching between CUDA and Ascend devices. Future work: - Add inference support for SGLang on Ascend NPUs. - Add training support for Megatron on Ascend NPUs. - Add training support for FSDP on Ascend NPUs. - Add support for vLLM versions >= 0.10. - Provide documentation with accuracy and performance benchmarks. Co-authored-by: noemotiovon <757486878@qq.com> Co-authored-by: FightingZhen <295632982@qq.com> Co-authored-by: lowdy1 <xiahouweidong@gmail.com>
1 parent 1f66a59 commit ccc21b4

55 files changed

Lines changed: 958 additions & 361 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/ascend/ascend_roll.md

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
# ROLL x Ascend
2+
3+
Last updated: 08/15/2025.
4+
5+
我们在 ROLL 上增加对华为昇腾设备的支持。
6+
7+
## 硬件支持
8+
9+
Atlas 200T A2 Box16
10+
11+
Atlas 900 A2 PODc
12+
13+
14+
## 安装
15+
16+
17+
### 基础环境准备
18+
19+
| software | version |
20+
|-----------|-------------|
21+
| Python | 3.10 |
22+
| CANN | 8.1.RC1 |
23+
24+
### 创建 conda 环境
25+
26+
27+
使用以下命令在 Miniconda 中创建新的 conda 环境:
28+
29+
```
30+
conda create --name roll python=3.10
31+
conda activate roll
32+
```
33+
34+
### 安装 torch & torch_npu:
35+
36+
37+
为了能在 ROLL 中正常使用 torch 和 torch_npu,需使用以下命令安装 torch 和 torch_npu。请注意根据机器类型区分安装方式。
38+
39+
```
40+
# 安装 torch 的 CPU 版本
41+
pip install torch==2.5.1 torchvision==0.20.1 torchaudio==2.5.1 --index-url https://download.pytorch.org/whl/cpu
42+
43+
# 安装 torch_npu
44+
pip install torch_npu==2.5.1
45+
```
46+
47+
48+
### 安装vllm & vllm-ascend:
49+
50+
为了能够在 ROLL 中正常使用 vllm,需使用以下命令编译安装 vllm 和 vllm-ascend。请注意根据机器类型区分安装方式。
51+
52+
```
53+
# vllm
54+
git clone -b v0.8.4 --depth 1 https://github.com/vllm-project/vllm.git
55+
cd vllm
56+
57+
VLLM_TARGET_DEVICE=empty pip install -v -e .
58+
cd ..
59+
```
60+
61+
```
62+
# vllm-ascend
63+
git clone -b v0.8.4rc2 --depth 1 https://github.com/vllm-project/vllm-ascend.git
64+
cd vllm-ascend
65+
66+
export COMPILE_CUSTOM_KERNELS=1
67+
pip install -e .
68+
cd ..
69+
```
70+
71+
如果在安装 vllm-ascend 时遇到类似以下问题:
72+
73+
```
74+
RuntimeError: CMake configuration failed: Command '['/pathto/miniconda3/envs/roll/bin/python3.10', '-m', 'pybind11', '--cmake']' returned non-zero exit status 2.
75+
```
76+
77+
可尝试在 vllm-ascend 目录下 setup.py 文件 151-158 行进行如下修改并重新进行编译:
78+
79+
```
80+
try:
81+
# if pybind11 is installed via pip
82+
pybind11_cmake_path = (subprocess.check_output(
83+
[python_executable, "-m", "pybind11",
84+
"--cmakedir"]).decode().strip())
85+
except subprocess.CalledProcessError as e:
86+
# else specify pybind11 path installed from source code on CI container
87+
raise RuntimeError(f"CMake configuration failed: {e}")
88+
```
89+
90+
### 安装 ROLL
91+
92+
```
93+
git clone https://github.com/alibaba/ROLL.git
94+
cd ROLL
95+
pip install -r requirements_common.txt
96+
pip install deepspeed==0.16.0
97+
cd ..
98+
```
99+
100+
### 其他三方库说明
101+
102+
| software | description |
103+
|-------------------------------|---------------|
104+
| transformers | v4.52.4 |
105+
| flash_attn | not supported |
106+
| tensordict | 0.8.3 (ARM) |
107+
| transformer-engine[pytorch] | not supported |
108+
109+
1. 支持通过 transformers 使能 --flash_attention_2, transformers 需大于等于 4.52.0版本。
110+
2. 不支持通过 flash_attn 使能 flash attention 加速。
111+
3. 针对 ARM 服务器,tensordict 要求 0.8.3,可在依赖安装完成后再手动安装 tensordict。
112+
4. 暂不支持 transformer-engine[pytorch]
113+
114+
```
115+
pip install transformers==4.52.4
116+
pip install tensordict==0.8.3
117+
```
118+
119+
## 快速开始,单节点部署指引
120+
121+
正式使用前,建议您通过对单节点流水线的训练尝试以检验环境准备和安装的正确性。
122+
由于目前暂不支持 Megatron-LM 训练,请首先将对应文件中
123+
strategy_args 参数修改为 deepspeed 选项。
124+
125+
1. 使用 shell 执行单节点流水线
126+
127+
```
128+
bash examples/agentic_demo/run_agentic_pipeline_frozen_lake_single_node_demo.sh
129+
```
130+
131+
2. 使用配置文件执行 agentic pipeline
132+
133+
```
134+
# 确保当前位于ROLL项目目录的根目录下
135+
# export PYTHONPATH=$(pwd):$PYTHONPATH
136+
137+
python examples/start_agentic_pipeline.py \
138+
--config_path qwen2.5-0.5B-agentic \
139+
--config_name agentic_val_sokoban
140+
141+
- ``--config_path`` – 包含您的YAML配置文件的目录。
142+
- ``--config_name`` – 文件名(不含.yaml后缀)。
143+
```
144+
145+
## 支持现状
146+
147+
148+
**表1** NPU 已通过流水线验证
149+
150+
| pipeline | hardware |
151+
|---------------------------------------------------------------|---------------------|
152+
| examples/qwen2.5-0.5B-agentic/run_agentic_pipeline_sokoban.sh | Atlas 900 A2 PODc |
153+
| examples/qwen2.5-0.5B-agentic/run_agentic_rollout_sokoban.sh | Atlas 900 A2 PODc |
154+
| examples/qwen2.5-1.5B-distill_ds/run_distill_pipeline.sh | Atlas 900 A2 PODc |
155+
| examples/qwen2.5-3B-dpo_megatron/run_dpo_pipeline.sh | Atlas 900 A2 PODc |
156+
| examples/qwen2.5-7B-rlvr_megatron/run_rlvr_pipeline.sh | Atlas 900 A2 PODc |
157+
158+
**表2** NPU 待流水线验证
159+
160+
| pipeline | hardware |
161+
|---------------------------------------------------------------|---------------------|
162+
| examples/qwen2.5-vl-7B-distill/run_distill_vl_ds_pipeline.sh | Atlas 900 A2 PODc |
163+
| examples/qwen2.5-vl-7B-rlvr/run_rlvr_pipeline.sh | Atlas 900 A2 PODc |
164+
165+
## 后续计划
166+
167+
168+
分别按照以下规则进行与 GPU 的精度与吞吐量的对比
169+
精度对比:
170+
根据经验,对于 Agentic 和 RLVR 等 RL 类算法,我们期望在相同配置下华为昇腾设备与 A100 的 rewards 平均绝对误差 <= 4%,计算方式参考下公式。
171+
```
172+
$ Mean Error = \frac{\sum_{i=1}^{N} |reward_i^{npu} - reward_{i}^{gpu}|}{N} \leq 0.04 $
173+
```
174+
对于 DPO 和 Distill 等类算法,我们期望在相同配置下华为昇腾设备与 A100 的 loss 相对误差 <= 4%,计算方式参考下公式。
175+
```
176+
$ Mean Error = \frac{\sum_{i=1}^{N} |loss_i^{npu} - loss_{i}^{gpu}|}{N} \leq 0.04 $
177+
```
178+
179+
吞吐对比:Ascend npu 和 A100 分别取日志中前4个 step 的 throughput 的 tpu 值 做平均, tpu ratio = npu 平均值 / A100 平均值。
180+
181+
182+
## 声明
183+
-----------------------------------
184+
ROLL 中提供的 Ascend 支持代码皆为参考样例,商业使用请通过官方正式途径沟通,谢谢。

mcore_adapter/src/mcore_adapter/initialize.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
from .training_args import TrainingArguments
99
from .utils import get_logger
1010

11+
from roll.platforms import current_platform
12+
1113

1214
logger = get_logger(__name__)
1315

@@ -28,7 +30,7 @@ def _set_random_seed(seed_):
2830
random.seed(seed)
2931
np.random.seed(seed)
3032
torch.manual_seed(seed)
31-
if torch.cuda.device_count() > 0:
33+
if current_platform.device_count() > 0:
3234
tensor_parallel.model_parallel_cuda_manual_seed(seed)
3335
else:
3436
raise ValueError("Seed ({}) should be a positive integer.".format(seed))
@@ -45,10 +47,10 @@ def _initialize_distributed(args: "TrainingArguments"):
4547
logger.info(f"Initializing mpu on device {args.device}")
4648
if not torch.distributed.is_initialized():
4749
# Manually set the device ids.
48-
torch.cuda.set_device(args.device)
50+
current_platform.set_device(args.device)
4951
# Call the init process
5052
torch.distributed.init_process_group(
51-
backend=args.ddp_backend or "nccl",
53+
backend=args.ddp_backend or current_platform.communication_backend,
5254
rank=int(os.getenv("RANK", "0")),
5355
world_size=int(os.getenv("WORLD_SIZE", "1")),
5456
timeout=args.ddp_timeout_delta,

mcore_adapter/src/mcore_adapter/models/converter/convert_utils.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import torch.distributed as dist
88
from megatron.core import mpu
99
from packaging.version import Version as PkgVersion
10+
from roll.platforms import current_platform
1011

1112

1213
if TYPE_CHECKING:
@@ -232,7 +233,7 @@ class StackedTensors:
232233

233234

234235
class TensorBucket:
235-
def __init__(self, bucket_size, device="cuda"):
236+
def __init__(self, bucket_size, device=current_platform.device_type):
236237
self.buffer = torch.empty(bucket_size, dtype=torch.int8, device=device)
237238
self.device = device
238239
self.bucket_size = bucket_size

mcore_adapter/src/mcore_adapter/models/model_factory.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from .converter.model_converter import ModelConverter
2626
from .model_config import McaModelConfig
2727
from .model_utils import ModuleUtilsMixin, RMSNorm, exists_hf_config, exists_mca_config
28+
from roll.platforms import current_platform
2829

2930

3031
if TYPE_CHECKING:
@@ -279,7 +280,7 @@ def __init__(self, config: "McaModelConfig", **kwargs):
279280
for param in self.parameters():
280281
tensor_parallel.set_defaults_if_not_set_tensor_model_parallel_attributes(param)
281282
if not config.use_cpu_initialization:
282-
self.cuda(torch.cuda.current_device())
283+
self.cuda(current_platform.current_device())
283284

284285
def _get_transformer_layer_spec(self, config: Optional["McaModelConfig"]=None):
285286
config = config or self.config

mcore_adapter/src/mcore_adapter/models/model_utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
from ..constants import MCA_CONFIG_NAME
99
from ..utils import get_logger
10-
10+
from roll.platforms import current_platform
1111

1212
if TYPE_CHECKING:
1313
from megatron.core.transformer import TransformerConfig
@@ -91,7 +91,7 @@ def floating_point_ops(
9191
class RMSNorm(nn.Module):
9292
def __init__(self, config: "TransformerConfig", hidden_size, eps=1e-6, **kwargs):
9393
super().__init__()
94-
device = torch.cuda.current_device() if not config.use_cpu_initialization else None
94+
device = current_platform.current_device() if not config.use_cpu_initialization else None
9595
self.weight = torch.nn.Parameter(torch.ones(hidden_size, dtype=config.params_dtype, device=device))
9696
self.variance_epsilon = eps
9797

mcore_adapter/src/mcore_adapter/models/qwen2_5_vl/modeling_qwen2_5_vl.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from megatron.core import mpu
55
from megatron.core.transformer.attention import SelfAttention
66
from torch import nn
7+
from roll.platforms import current_platform
78

89
from ..auto.modeling_auto import register_model
910
from ..model_factory import McaGPTModel
@@ -58,7 +59,7 @@ def __init__(
5859
if rotary_percent < 1.0:
5960
dim = int(dim * rotary_percent)
6061

61-
device = "cpu" if use_cpu_initialization else torch.cuda.current_device()
62+
device = "cpu" if use_cpu_initialization else current_platform.current_device()
6263
self.inv_freq = 1.0 / (rotary_base ** (torch.arange(0, dim, 2, dtype=torch.float32, device=device) / dim))
6364

6465
@torch.no_grad()
@@ -199,7 +200,7 @@ def __init__(self, config: "Qwen2_5_VLConfig", **kwargs):
199200
Qwen2_5_VLVisionConfig(**config.vision_config),
200201
attn_implementation="flash_attention_2",
201202
torch_dtype=self.config.params_dtype,
202-
).to(torch.cuda.current_device())
203+
).to(current_platform.current_device())
203204
for param in self.vision_model.parameters():
204205
setattr(param, "sequence_parallel", config.sequence_parallel)
205206

mcore_adapter/src/mcore_adapter/models/qwen2_vl/modeling_qwen2_vl.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from megatron.core import mpu
55
from megatron.core.transformer.attention import SelfAttention
66
from torch import nn
7+
from roll.platforms import current_platform
78

89
from ..auto.modeling_auto import register_model
910
from ..model_factory import McaGPTModel
@@ -61,7 +62,7 @@ def __init__(
6162
self.rotary_interleaved = rotary_interleaved
6263

6364
self.seq_len_interpolation_factor = seq_len_interpolation_factor
64-
device = "cpu" if use_cpu_initialization else torch.cuda.current_device()
65+
device = "cpu" if use_cpu_initialization else current_platform.current_device()
6566
self.inv_freq = 1.0 / (rotary_base ** (torch.arange(0, dim, 2, dtype=torch.float32, device=device) / dim))
6667

6768
@torch.no_grad()
@@ -204,7 +205,7 @@ def __init__(self, config: "Qwen2VLConfig", **kwargs):
204205
Qwen2VLVisionConfig(**config.vision_config),
205206
attn_implementation="sdpa",
206207
torch_dtype=self.config.params_dtype,
207-
).to(torch.cuda.current_device())
208+
).to(current_platform.current_device())
208209
for param in self.vision_model.parameters():
209210
setattr(param, "sequence_parallel", config.sequence_parallel)
210211

mcore_adapter/src/mcore_adapter/trainer/trainer.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
seed_worker,
3737
speed_metrics,
3838
)
39+
from roll.platforms import current_platform
3940

4041
from ..checkpointing import get_checkpoint_dir, load_state_dict_from_checkpoint
4142
from ..constants import DIST_OPTIMIZER_DIR, IGNORE_INDEX
@@ -501,7 +502,7 @@ def _save_rng_state(self, output_dir):
501502
"random_rng_state": random.getstate(),
502503
"np_rng_state": np.random.get_state(),
503504
"torch_rng_state": torch.get_rng_state(),
504-
"cuda_rng_state": torch.cuda.get_rng_state(),
505+
"cuda_rng_state": current_platform.get_rng_state(),
505506
"rng_tracker_states": tensor_parallel.get_cuda_rng_tracker().get_states(),
506507
}
507508
if self.args.world_size <= 1:
@@ -537,7 +538,7 @@ def _load_rng_state(self, checkpoint):
537538
random.setstate(checkpoint_rng_state["random_rng_state"])
538539
np.random.set_state(checkpoint_rng_state["np_rng_state"])
539540
torch.set_rng_state(checkpoint_rng_state["torch_rng_state"])
540-
torch.cuda.set_rng_state(checkpoint_rng_state["cuda_rng_state"])
541+
current_platform.set_rng_state(checkpoint_rng_state["cuda_rng_state"])
541542
# Check for empty states array
542543
if not checkpoint_rng_state["rng_tracker_states"]:
543544
raise KeyError

0 commit comments

Comments
 (0)