From b789503e8fb02fde84f2f878324d33324275ddd6 Mon Sep 17 00:00:00 2001 From: cyb <694642680@qq.com> Date: Mon, 14 Sep 2026 16:43:10 +0800 Subject: [PATCH] =?UTF-8?q?[feature]=E6=94=AF=E6=8C=81xDiT=E7=9A=84quick?= =?UTF-8?q?=20start=E6=96=87=E6=A1=A3=E6=B5=8B=E8=AF=95=E7=9C=8B=E6=8A=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/xdit-quick-start.yml | 34 ++++++ _static/images/xdit.png | Bin 0 -> 13838 bytes conf.py | 3 +- index.rst | 8 ++ sources/xdit/index.rst | 2 + sources/xdit/quick_start.md | 162 +++++++++++++++++++++++++ tests/xdit/__init__.py | 13 ++ tests/xdit/test_quick_start_ascend.py | 162 +++++++++++++++++++++++++ 8 files changed, 383 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/xdit-quick-start.yml create mode 100644 _static/images/xdit.png create mode 100644 sources/xdit/index.rst create mode 100644 sources/xdit/quick_start.md create mode 100644 tests/xdit/__init__.py create mode 100644 tests/xdit/test_quick_start_ascend.py diff --git a/.github/workflows/xdit-quick-start.yml b/.github/workflows/xdit-quick-start.yml new file mode 100644 index 000000000..c11d2dd0c --- /dev/null +++ b/.github/workflows/xdit-quick-start.yml @@ -0,0 +1,34 @@ +# xdit quick start guard - thin trigger over quick-start-template.yml; the engine owns the monitor loop, cache I/O and result publishing. +name: xdit-quick-start + +concurrency: + group: ${{ github.event_name == 'schedule' && 'xdit-quick-start-schedule' || format('manual-{0}', github.run_id) }} + cancel-in-progress: false + +on: + schedule: + - cron: '45 */6 * * *' + workflow_dispatch: + pull_request: + branches: [main] + paths: + - 'sources/xdit/**' + - 'tests/xdit/**' + +permissions: + contents: read + +jobs: + xdit-quick-start: + uses: ./.github/workflows/quick-start-template.yml + with: + project: xdit + test_runner: '["linux-aarch64-a2-2"]' + image: swr.cn-south-1.myhuaweicloud.com/ascendhub/cann:9.1.0-910b-ubuntu22.04-py3.12 + container_options: >- + --volume=/data/ci-cache/modelscope/xdit:/root/.cache/modelscope:z + timeout_minutes: 90 + upstream_repo: xdit-project/xDiT + doc_url: 'https://raw.githubusercontent.com/Ascend/docs/{0}/sources/xdit/quick_start.md' + doc_path: https://github.com/Ascend/docs/blob/main/sources/xdit/quick_start.md + test_command: python -m unittest tests.xdit.test_quick_start_ascend -v 2>&1 diff --git a/_static/images/xdit.png b/_static/images/xdit.png new file mode 100644 index 0000000000000000000000000000000000000000..856ef9ebc99c2332580ba57a4c9c74ee47a2b2d1 GIT binary patch literal 13838 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 QL;wH)07*qoM6N<$f@-0@1poj5 literal 0 HcmV?d00001 diff --git a/conf.py b/conf.py index 5bc93024e..902c063be 100644 --- a/conf.py +++ b/conf.py @@ -77,7 +77,8 @@ 'sources/llama_cpp/quick_start.md', 'sources/whisper_cpp/quick_start.md', 'sources/llm_compressor/quick_start.md', - 'sources/axolotl/quick_start.md'] + 'sources/axolotl/quick_start.md', + 'sources/xdit/quick_start.md'] # -- Options for HTML output ------------------------------------------------- diff --git a/index.rst b/index.rst index 9c4356f98..e2e19f3d4 100644 --- a/index.rst +++ b/index.rst @@ -336,6 +336,13 @@

扩散模型工具链,支持昇腾 NPU 加速图像生成。

+ +
+

xDiT

+

扩散模型推理加速框架,支持昇腾 NPU 单卡/多卡加速图像生成。

+ +
+
@@ -463,6 +470,7 @@ :caption: 🎨 多模态、应用与评测 sources/Diffusers/index.rst + sources/xdit/index.rst sources/lm_evaluation/index.rst sources/open_clip/index.rst sources/opencompass/index.rst diff --git a/sources/xdit/index.rst b/sources/xdit/index.rst new file mode 100644 index 000000000..89892f3b6 --- /dev/null +++ b/sources/xdit/index.rst @@ -0,0 +1,2 @@ +.. include:: quick_start.md + :parser: myst_parser.sphinx_ diff --git a/sources/xdit/quick_start.md b/sources/xdit/quick_start.md new file mode 100644 index 000000000..63dc22d9a --- /dev/null +++ b/sources/xdit/quick_start.md @@ -0,0 +1,162 @@ +# xDiT + +xDiT(PyPI 包名 `xfuser`)是一套统一的并行推理框架。本示例在单卡昇腾 NPU 上生成第一张图。 + +## 前置条件 + +### 硬件 + +Atlas 900 A2 训练服务器(Ascend 910B),并按需完成物理机或容器内的设备挂载。单卡生成示例需 1 张卡,序列并行示例需 2 张卡。 + +### 基础软件 + +在运行本文档示例之前,你的机器上需要已经装好并可用: + +- 可用的 Python 环境 +- 可用的 CANN(参考[快速安装昇腾环境](https://ascend.github.io/docs/sources/ascend/quick_install.html)) + +本文档示例在 Python 3.12、CANN 9.1.0 环境下验证通过。 + +## 加载 CANN 环境 + +```shell +source /usr/local/Ascend/ascend-toolkit/set_env.sh +``` + +## 安装 PyTorch NPU 栈 + +参考的版本配套如下(更多组合见 [CANN 与 PyTorch 配套表](https://github.com/Ascend/pytorch/blob/master/COMPATIBILITY.md)): + +| CANN | PyTorch | `torch_npu` 安装包 | +| --- | --- | --- | +| 9.1.0 | 2.9.0 | 2.9.0.post6 | +| 9.1.0 | 2.10.0 | 2.10.0.post4 | +| 9.1.0 | 2.11.0 | 2.11.0 | + +本示例使用第一行的组合: + +```shell #test-setup id="xdit-install-torch" +pip install torch==2.9.0 torch_npu==2.9.0.post6 +``` + +## 安装 xDiT + +安装 `xfuser`(PyPI 包名),并打印安装版本: + +```shell #test id="xdit-install" +pip install xfuser +python -c "from importlib.metadata import version; print('xDiT version:', version('xfuser'))" +``` + +输出结果如下: + +```shell #test-result id="xdit-install" fuzzy='...' fuzzy='xxx' +... +xDiT version: xxx +``` + +其中 `xxx` 是安装的 xDiT(`xfuser`)版本号。 + +## 运行示例:文生图 + +安装示例使用的 Triton 和模型下载所需的 ModelScope: + +```shell #test-setup +pip install triton==3.5.0 "modelscope==1.37.0" +``` + +用 [SD3 medium](https://modelscope.cn/models/stabilityai/stable-diffusion-3-medium-diffusers) 在单卡上生成一张 256×256 的图。模型约 28 GB。 + +将下面的 Python 代码保存为 `sd3_npu.py`: + +```python +import os +import sys +import time + +import torch +import torch_npu +from modelscope import snapshot_download +from transformers import T5EncoderModel +from xfuser import xFuserArgs, xFuserStableDiffusion3Pipeline +from xfuser.config import FlexibleArgumentParser +from xfuser.core.distributed import get_runtime_state, get_world_group + +model_path = snapshot_download('stabilityai/stable-diffusion-3-medium-diffusers') + +parser = FlexibleArgumentParser(description="xFuser SD3 Arguments") +args = xFuserArgs.add_cli_args(parser).parse_args(['--model', model_path] + sys.argv[1:]) +engine_args = xFuserArgs.from_cli_args(args) +engine_config, input_config = engine_args.create_config() +local_rank = get_world_group().rank + +text_encoder_3 = T5EncoderModel.from_pretrained( + model_path, subfolder="text_encoder_3", dtype=torch.float16 +) +pipe = xFuserStableDiffusion3Pipeline.from_pretrained( + pretrained_model_name_or_path=model_path, + engine_config=engine_config, + dtype=torch.float16, + text_encoder_3=text_encoder_3, +).to(f"npu:{local_rank}") +pipe.prepare_run(input_config) + +torch.npu.synchronize(device=local_rank) +start = time.perf_counter() +output = pipe( + height=input_config.height, + width=input_config.width, + prompt=input_config.prompt, + num_inference_steps=input_config.num_inference_steps, + output_type=input_config.output_type, + guidance_scale=input_config.guidance_scale, + generator=torch.Generator(device="npu").manual_seed(input_config.seed), +) +torch.npu.synchronize(device=local_rank) +elapsed = time.perf_counter() - start + +os.makedirs("results", exist_ok=True) +if pipe.is_dp_last_group(): + world_size = get_world_group().world_size + path = f"results/sd3_npu{world_size}_ulysses{engine_args.ulysses_degree}.png" + output.images[0].save(path) + print(f"inference time: {elapsed:.2f} sec") + print(f"image saved to {path}") +get_runtime_state().destroy_distributed_env() +``` + +用 `torchrun` 在单卡上运行: + +```shell #test id="xdit-sd3-smoke" +torchrun --nproc_per_node=1 sd3_npu.py --prompt "a tiny test sketch" --height 256 --width 256 --num_inference_steps 1 --seed 42 +``` + +输出结果如下: + +```shell #test-result id="xdit-sd3-smoke" fuzzy='...' fuzzy='xxx' +... +inference time: xxx sec +image saved to results/sd3_npu1_ulysses1.png +``` + +### 多卡运行示例 + +同一个脚本、同一个模型,加 `--ulysses_degree 2` 在 2 卡上做序列并行,attention 用 SDPA 后端: + +```shell #test id="xdit-sd3-2card" +torchrun --nproc_per_node=2 sd3_npu.py --prompt "a tiny test sketch" --height 256 --width 256 --num_inference_steps 1 --seed 42 --ulysses_degree 2 --attention_backend SDPA +``` + +输出结果如下: + +```shell #test-result id="xdit-sd3-2card" fuzzy='...' fuzzy='xxx' +... +inference time: xxx sec +image saved to results/sd3_npu2_ulysses2.png +``` + +其中 `xxx` 为实际推理耗时,单位为秒。 + +## 更多用法 + +更多模型与多卡并行(PipeFusion / CFG 并行 / Ring 等)见 [xDiT examples](https://github.com/xdit-project/xDiT/tree/main/examples)。 diff --git a/tests/xdit/__init__.py b/tests/xdit/__init__.py new file mode 100644 index 000000000..3767dfb23 --- /dev/null +++ b/tests/xdit/__init__.py @@ -0,0 +1,13 @@ +"""Tests package marker (injects repo tests/ into sys.path).""" + +from __future__ import annotations + +import sys +from pathlib import Path + +_REPO_ROOT = Path(__file__).resolve().parents[2] +_TESTS_ROOT = _REPO_ROOT / 'tests' +for _p in (_TESTS_ROOT, _REPO_ROOT): + _ps = str(_p) + if _ps not in sys.path: + sys.path.insert(0, _ps) diff --git a/tests/xdit/test_quick_start_ascend.py b/tests/xdit/test_quick_start_ascend.py new file mode 100644 index 000000000..8abe2d3e9 --- /dev/null +++ b/tests/xdit/test_quick_start_ascend.py @@ -0,0 +1,162 @@ +"""Quick-start-Ascend test: doc under test is sources/xdit/quick_start.md.""" + +from __future__ import annotations + +import os +import re +import subprocess +import unittest +from pathlib import Path + +from doc_test.base import MarkdownDocTestBase, TestCommand +from doc_test.model_cache import ( + ensure_safetensors, + purge_modelscope_corrupt, + resolve_modelscope_cache, +) + + +def _is_truthy(value: str | None) -> bool: + if not value: + return False + return value.strip().lower() == "true" + + +def _e2e_enabled() -> bool: + return _is_truthy(os.environ.get("NPU_READY")) + + +def _write_example_script(document: str) -> None: + """Write the single reader-facing Python example into the test cwd.""" + blocks = re.findall(r"(?ms)^```python[ \t]*\r?\n(.*?)^```[ \t]*$", document) + if len(blocks) != 1: + raise AssertionError(f"expected one unlabeled Python example, found {len(blocks)}") + script = blocks[0].rstrip() + "\n" + compile(script, "sd3_npu.py", "exec") + Path("sd3_npu.py").write_text(script, encoding="utf-8") + + +class TestQuickStartAscend(MarkdownDocTestBase, unittest.TestCase): + """SD3 medium smoke on 1 card + 2-card Ulysses parallel (NPU/hccl).""" + + DEFAULT_COMMAND_TIMEOUT = 1800 + USER_AGENT = "cosdt-ci-test/quick-start" + ERROR_MARKERS = ( + *MarkdownDocTestBase.ERROR_MARKERS, + ) + + _CUDA_CONSTRAINTS = ( + "cuda-toolkit<0", "cuda-python<0", "cuda-bindings<0", "cuda-core<0", "cuda-pathfinder<0", + "flashinfer-python<0", "nvidia-cublas<0", "nvidia-cuda-runtime<0", "nvidia-cuda-nvrtc<0", + "nvidia-cuda-cupti<0", "nvidia-cudnn<0", "nvidia-cudnn-frontend<0", "nvidia-cufft<0", + "nvidia-curand<0", "nvidia-cusolver<0", "nvidia-cusparse<0", "nvidia-cutlass-dsl<0", + "nvidia-cutlass-dsl-libs-base<0", "nvidia-cutlass-dsl-libs-core<0", "nvidia-cutlass-dsl-libs-cu12<0", + "nvidia-ml-py<0", "nvidia-nccl<0", "nvidia-nvjitlink<0", "nvidia-nvtx<0", + "nvidia-cublas-cu12<0", "nvidia-cuda-nvdisasm<0", "nvidia-cuda-runtime-cu12<0", "nvidia-cuda-nvrtc-cu12<0", + "nvidia-cuda-cupti-cu12<0", "nvidia-cudnn-cu12<0", "nvidia-cufft-cu12<0", "nvidia-curand-cu12<0", + "nvidia-cusolver-cu12<0", "nvidia-cusparse-cu12<0", "nvidia-cusparselt-cu12<0", "nvidia-nccl-cu12<0", + "nvidia-nvjitlink-cu12<0", "nvidia-nvtx-cu12<0", + ) + _CONSTRAINTS_FILE = "/tmp/xdit_npu_constraints.txt" + _CANN_SET_ENV = "/usr/local/Ascend/ascend-toolkit/set_env.sh" + _PROJECT_ROOT = Path("/root/xdit-test") + _GENERATED_PNGS = { + "xdit-sd3-smoke": Path("results/sd3_npu1_ulysses1.png"), + "xdit-sd3-2card": Path("results/sd3_npu2_ulysses2.png"), + } + + def _verify_generated_png(self, path: Path) -> None: + """Keep the PNG integrity check in CI, not in the quick start.""" + if not path.is_file(): + raise AssertionError(f"generated image not found: {path}") + image = path.read_bytes() + if len(image) <= 50_000: + raise AssertionError( + "generated image is suspiciously small " + f"({len(image)} bytes): {path}" + ) + if image[:8] != b"\x89PNG\r\n\x1a\n": + raise AssertionError( + "generated image is not a PNG " + f"(magic={image[:8]!r}): {path}" + ) + self.log( + f"[Step] verified generated PNG ({len(image)}B): " + f"{path}" + ) + + def _run_one(self, cmd, results, env, cwd, timeout, idx): + if isinstance(cmd, TestCommand) and cmd.id in self._GENERATED_PNGS: + super()._run_one(cmd, results, env, cwd, timeout, idx) + self._verify_generated_png(self._GENERATED_PNGS[cmd.id]) + return + return super()._run_one(cmd, results, env, cwd, timeout, idx) + + def pre_process(self) -> str: + doc = Path(__file__).resolve().parent.parent.parent / "sources" / "xdit" / "quick_start.md" + document = doc.read_text(encoding="utf-8") + _write_example_script(document) + return document + + @classmethod + def prepare_environment(cls) -> None: + if os.path.isfile(cls._CANN_SET_ENV): + merged = subprocess.run( + ["bash", "-c", f"source {cls._CANN_SET_ENV} >/dev/null 2>&1; env"], + capture_output=True, text=True, check=True, + ) + for line in merged.stdout.splitlines(): + if "=" not in line: + continue + key, _, value = line.partition("=") + os.environ.setdefault(key, value) + print("setup: sourced CANN env from set_env.sh") + else: + print(f"setup: skipping CANN env source ({cls._CANN_SET_ENV} not present)") + + with open(cls._CONSTRAINTS_FILE, "w", encoding="utf-8") as f: + f.write(chr(10).join(cls._CUDA_CONSTRAINTS) + chr(10)) + os.environ["PIP_CONSTRAINT"] = cls._CONSTRAINTS_FILE + + # purge stale xfuser from the image so the doc install block really + # installs the PyPI release instead of keeping a baked-in copy + subprocess.run(["python", "-m", "pip", "uninstall", "-y", "xfuser"], + capture_output=True, text=True, check=False) + + # Run the documented script and write results outside the repository. + os.makedirs(cls._PROJECT_ROOT, exist_ok=True) + os.chdir(cls._PROJECT_ROOT) + print(f"setup: cwd -> {cls._PROJECT_ROOT}") + + ps = "import torch, torch_npu\nraise SystemExit(0 if torch.npu.is_available() else 1)\n" + probe = subprocess.run(["python", "-c", ps], capture_output=True, check=False) + if probe.returncode == 0: + vs = subprocess.run(["python", "-c", "import torch, torch_npu; print(torch.__version__, torch_npu.__version__)"], + capture_output=True, text=True, check=True) + print(f"setup: reusing image torch stack ({vs.stdout.strip()})") + else: + print("setup: torch probe failed, doc install-torch will install the pinned stack") + + os.environ["ASCEND_RT_VISIBLE_DEVICES"] = "0,1" + + ensure_safetensors() + try: + purge_modelscope_corrupt(resolve_modelscope_cache()) + except Exception as e: + print(f"setup: cache purge skipped ({e})") + + @classmethod + def setUpClass(cls) -> None: + if _e2e_enabled(): + cls.prepare_environment() + + @unittest.skipIf( + not _e2e_enabled(), + "end-to-end requires NPU runner; set NPU_READY=true", + ) + def test_runs_doc(self) -> None: + self.run_template() + + +if __name__ == "__main__": + unittest.main()