Skip to content

[platform]: add scripts and adapt for ascend, mlu, metal#1208

Open
Watebear wants to merge 17 commits into
mainfrom
ascend
Open

[platform]: add scripts and adapt for ascend, mlu, metal#1208
Watebear wants to merge 17 commits into
mainfrom
ascend

Conversation

@Watebear

@Watebear Watebear commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

No description provided.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces multi-platform support (Ascend NPU, Cambricon MLU, MetaX, and NVIDIA) for several text-to-image and text-to-video models, adding single-card and distributed (tensor-parallel and sequence-parallel) configurations along with platform-specific launcher scripts. Key changes include tensor-parallel weight loading for Flux2, sequence-parallel support for LongCat Image, and directory restructuring. The code review identified several critical issues: potential device mismatches when registering buffers on CPU, missing safety guards for uninitialized distributed environments in Flux2, a shape mismatch in HunyuanVideo's NPU attention output, an uninitialized sequence-parallel group attribute in LongCat Image, and invalid parameter usage in F.pad with replicate mode. Additionally, several test files and scripts contain broken file paths due to the directory restructuring and config renames, which need to be updated to prevent runtime and test failures.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +144 to +148
def _register_or_replace_buffer(module: torch.nn.Module, name: str, value: torch.Tensor) -> None:
if name in module._buffers:
module._buffers[name] = value
else:
module.register_buffer(name, value)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

If _register_or_replace_buffer is called after the model has been moved to a non-CPU device (e.g., GPU or NPU), registering a CPU tensor as a buffer will keep it on the CPU. This can lead to device mismatch errors during the forward pass. We should dynamically cast the tensor to the device of the module's existing parameters or buffers.

Suggested change
def _register_or_replace_buffer(module: torch.nn.Module, name: str, value: torch.Tensor) -> None:
if name in module._buffers:
module._buffers[name] = value
else:
module.register_buffer(name, value)
def _register_or_replace_buffer(module: torch.nn.Module, name: str, value: torch.Tensor) -> None:
parameter = next(module.parameters(), None)
if parameter is not None:
value = value.to(parameter.device)
else:
buf = next(module.buffers(), None)
if buf is not None:
value = value.to(buf.device)
if name in module._buffers:
module._buffers[name] = value
else:
module.register_buffer(name, value)

Comment on lines +33 to +43
def _init_tensor_parallel(self):
if self.config.get("tensor_parallel", False):
self.use_tp = True
self.tp_group = self.config.get("device_mesh").get_group(mesh_dim="tensor_p")
self.tp_rank = dist.get_rank(self.tp_group)
self.tp_size = dist.get_world_size(self.tp_group)
else:
self.use_tp = False
self.tp_group = None
self.tp_rank = 0
self.tp_size = 1

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

If tensor_parallel is enabled but dist.is_initialized() is False or device_mesh is None, calling get_group or dist.get_rank will raise an error. We should add safety guards to ensure distributed is initialized and device_mesh is present before attempting to initialize tensor parallel.

Suggested change
def _init_tensor_parallel(self):
if self.config.get("tensor_parallel", False):
self.use_tp = True
self.tp_group = self.config.get("device_mesh").get_group(mesh_dim="tensor_p")
self.tp_rank = dist.get_rank(self.tp_group)
self.tp_size = dist.get_world_size(self.tp_group)
else:
self.use_tp = False
self.tp_group = None
self.tp_rank = 0
self.tp_size = 1
def _init_tensor_parallel(self):
if self.config.get("tensor_parallel", False) and dist.is_initialized() and self.config.get("device_mesh") is not None:
self.use_tp = True
self.tp_group = self.config.get("device_mesh").get_group(mesh_dim="tensor_p")
self.tp_rank = dist.get_rank(self.tp_group)
self.tp_size = dist.get_world_size(self.tp_group)
else:
self.use_tp = False
self.tp_group = None
self.tp_rank = 0
self.tp_size = 1

Comment on lines +89 to +91
out = torch.zeros(batch * seqlen, heads * dim, dtype=out_unpad.dtype, device=out_unpad.device)
out[indices] = out_unpad
return out.reshape(batch, seqlen, heads, dim)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The out_unpad tensor returned by npu_flash_attn has shape [total_unpadded_tokens, heads, dim]. Initializing out with shape [batch * seqlen, heads * dim] will cause a shape mismatch error when executing out[indices] = out_unpad. We should initialize out with shape [batch * seqlen, heads, dim] to match the unpadded tensor dimensions.

Suggested change
out = torch.zeros(batch * seqlen, heads * dim, dtype=out_unpad.dtype, device=out_unpad.device)
out[indices] = out_unpad
return out.reshape(batch, seqlen, heads, dim)
out = torch.zeros(batch * seqlen, heads, dim, dtype=out_unpad.dtype, device=out_unpad.device)
out[indices] = out_unpad
return out.reshape(batch, seqlen, heads, dim)

Comment on lines 30 to 35
# Use transformer_in_channels to avoid conflict with VAE's in_channels
self.in_channels = self.config.get("transformer_in_channels", self.config.get("in_channels", 64))
self.attention_kwargs = {}
if self.config["seq_parallel"]:
raise NotImplementedError("Sequence parallel is not implemented for LongCatImageTransformerModel")
self._init_infer_class()
self._init_weights()
self._init_infer()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

When seq_parallel is enabled, _seq_parallel_pre_process and _seq_parallel_post_process access self.seq_p_group. However, self.seq_p_group is never initialized in LongCatImageTransformerModel.__init__, which will raise an AttributeError at runtime. We should initialize self.seq_p_group from the device mesh during model initialization.

        # Use transformer_in_channels to avoid conflict with VAE's in_channels
        self.in_channels = self.config.get("transformer_in_channels", self.config.get("in_channels", 64))
        self.attention_kwargs = {}
        if self.config.get("seq_parallel", False) and self.config.get("device_mesh") is not None:
            self.seq_p_group = self.config.get("device_mesh").get_group(mesh_dim="seq_p")
        else:
            self.seq_p_group = None
        self._init_infer_class()
        self._init_weights()
        self._init_infer()

Comment on lines +40 to +43
def _pad(x: torch.Tensor, pad, mode: str = "constant", value: float = 0.0) -> torch.Tensor:
if mode == "replicate" and PLATFORM in _REPLICATE_PAD_FLOAT32_PLATFORMS and x.dtype == torch.bfloat16:
return F.pad(x.float(), pad, mode=mode, value=value).to(dtype=x.dtype)
return F.pad(x, pad, mode=mode, value=value)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

In PyTorch, F.pad does not accept the value parameter when mode is "replicate". Passing value=value to F.pad with mode="replicate" will raise a ValueError. We should only pass value when mode is "constant".

Suggested change
def _pad(x: torch.Tensor, pad, mode: str = "constant", value: float = 0.0) -> torch.Tensor:
if mode == "replicate" and PLATFORM in _REPLICATE_PAD_FLOAT32_PLATFORMS and x.dtype == torch.bfloat16:
return F.pad(x.float(), pad, mode=mode, value=value).to(dtype=x.dtype)
return F.pad(x, pad, mode=mode, value=value)
def _pad(x: torch.Tensor, pad, mode: str = "constant", value: float = 0.0) -> torch.Tensor:
if mode == "replicate" and PLATFORM in _REPLICATE_PAD_FLOAT32_PLATFORMS and x.dtype == torch.bfloat16:
return F.pad(x.float(), pad, mode=mode).to(dtype=x.dtype)
if mode == "constant":
return F.pad(x, pad, mode=mode, value=value)
return F.pad(x, pad, mode=mode)

Comment on lines +59 to +64
def test_hy15_dist8_config_and_launcher_default_to_single_card_alignment():
config = json.loads(Path("configs/platforms/nvidia/dist_8/hunyuan_video_t2v_480p.json").read_text(encoding="utf-8"))
script = Path("scripts/platforms/nvidia/dist_8/run_hy15_t2v_480p.sh").read_text(encoding="utf-8")

assert config["align_single_card_shape"] is True
assert "gpus=${GPUS:-8}" in script

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The test file references configs/platforms/nvidia/dist_8/hunyuan_video_t2v_480p.json and scripts/platforms/nvidia/dist_8/run_hy15_t2v_480p.sh. However, the directory was renamed to dist and the config file was renamed to hunyuan_video_t2v_480p_dist8.json. This will cause a FileNotFoundError when running the tests. We should update the paths to match the new directory structure.

Suggested change
def test_hy15_dist8_config_and_launcher_default_to_single_card_alignment():
config = json.loads(Path("configs/platforms/nvidia/dist_8/hunyuan_video_t2v_480p.json").read_text(encoding="utf-8"))
script = Path("scripts/platforms/nvidia/dist_8/run_hy15_t2v_480p.sh").read_text(encoding="utf-8")
assert config["align_single_card_shape"] is True
assert "gpus=${GPUS:-8}" in script
def test_hy15_dist8_config_and_launcher_default_to_single_card_alignment():
config = json.loads(Path("configs/platforms/nvidia/dist/hunyuan_video_t2v_480p_dist8.json").read_text(encoding="utf-8"))
script = Path("scripts/platforms/nvidia/dist/run_hy15_t2v_480p.sh").read_text(encoding="utf-8")
assert config["align_single_card_shape"] is True
assert "gpus=${GPUS:-8}" in script

Comment thread tests/test_z_image_dist_config.py Outdated
Comment on lines +5 to +15
def test_z_image_nvidia_dist_uses_head_divisible_seq_parallel():
config = json.loads(Path("configs/platforms/nvidia/dist_8/z_image_turbo_t2i.json").read_text(encoding="utf-8"))
script = Path("scripts/platforms/nvidia/dist_8/z_image_turbo_t2i.sh").read_text(encoding="utf-8")

assert config["enable_cfg"] is False
assert config["parallel"] == {
"seq_p_size": 2,
"seq_p_attn_type": "ulysses",
}
assert "gpus=${GPUS:-2}" in script
assert 'CUDA_VISIBLE_DEVICES="${CUDA_VISIBLE_DEVICES:-4,5}"' in script

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The test file references configs/platforms/nvidia/dist_8/z_image_turbo_t2i.json and scripts/platforms/nvidia/dist_8/z_image_turbo_t2i.sh. However, the directory was renamed to dist and the config file was renamed to z_image_turbo_t2i_dist2.json. This will cause a FileNotFoundError when running the tests. We should update the paths to match the new directory structure.

Suggested change
def test_z_image_nvidia_dist_uses_head_divisible_seq_parallel():
config = json.loads(Path("configs/platforms/nvidia/dist_8/z_image_turbo_t2i.json").read_text(encoding="utf-8"))
script = Path("scripts/platforms/nvidia/dist_8/z_image_turbo_t2i.sh").read_text(encoding="utf-8")
assert config["enable_cfg"] is False
assert config["parallel"] == {
"seq_p_size": 2,
"seq_p_attn_type": "ulysses",
}
assert "gpus=${GPUS:-2}" in script
assert 'CUDA_VISIBLE_DEVICES="${CUDA_VISIBLE_DEVICES:-4,5}"' in script
def test_z_image_nvidia_dist_uses_head_divisible_seq_parallel():
config = json.loads(Path("configs/platforms/nvidia/dist/z_image_turbo_t2i_dist2.json").read_text(encoding="utf-8"))
script = Path("scripts/platforms/nvidia/dist/z_image_turbo_t2i.sh").read_text(encoding="utf-8")
assert config["enable_cfg"] is False
assert config["parallel"] == {
"seq_p_size": 2,
"seq_p_attn_type": "ulysses",
}
assert "gpus=${GPUS:-2}" in script
assert 'CUDA_VISIBLE_DEVICES="${CUDA_VISIBLE_DEVICES:-4,5}"' in script

Comment thread tests/test_longcat_seq_parallel.py Outdated
Comment on lines +95 to +111
def test_longcat_nvidia_dist8_launcher_uses_torchrun():
script = Path("scripts/platforms/nvidia/dist_8/longcat_image_t2i.sh").read_text(encoding="utf-8")

assert 'torchrun --nproc_per_node="${gpus}" -m lightx2v.infer' in script
assert "gpus=${GPUS:-8}" in script
assert "python -m lightx2v.infer" not in script


def test_longcat_nvidia_dist8_config_matches_qwen_image_parallel_layout():
with open("configs/platforms/nvidia/dist_8/longcat_image_t2i.json", "r", encoding="utf-8") as f:
config = json.load(f)

assert config["parallel"] == {
"seq_p_size": 4,
"seq_p_attn_type": "ulysses",
"cfg_p_size": 2,
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The test file references configs/platforms/nvidia/dist_8/longcat_image_t2i.json and scripts/platforms/nvidia/dist_8/longcat_image_t2i.sh. However, the directory was renamed to dist and the config file was renamed to longcat_image_t2i_dist8.json. This will cause a FileNotFoundError when running the tests. We should update the paths to match the new directory structure.

Suggested change
def test_longcat_nvidia_dist8_launcher_uses_torchrun():
script = Path("scripts/platforms/nvidia/dist_8/longcat_image_t2i.sh").read_text(encoding="utf-8")
assert 'torchrun --nproc_per_node="${gpus}" -m lightx2v.infer' in script
assert "gpus=${GPUS:-8}" in script
assert "python -m lightx2v.infer" not in script
def test_longcat_nvidia_dist8_config_matches_qwen_image_parallel_layout():
with open("configs/platforms/nvidia/dist_8/longcat_image_t2i.json", "r", encoding="utf-8") as f:
config = json.load(f)
assert config["parallel"] == {
"seq_p_size": 4,
"seq_p_attn_type": "ulysses",
"cfg_p_size": 2,
}
def test_longcat_nvidia_dist8_launcher_uses_torchrun():
script = Path("scripts/platforms/nvidia/dist/longcat_image_t2i.sh").read_text(encoding="utf-8")
assert 'torchrun --nproc_per_node="${gpus}" -m lightx2v.infer' in script
assert "gpus=${GPUS:-8}" in script
assert "python -m lightx2v.infer" not in script
def test_longcat_nvidia_dist8_config_matches_qwen_image_parallel_layout():
with open("configs/platforms/nvidia/dist/longcat_image_t2i_dist8.json", "r", encoding="utf-8") as f:
config = json.load(f)
assert config["parallel"] == {
"seq_p_size": 4,
"seq_p_attn_type": "ulysses",
"cfg_p_size": 2,
}

Comment on lines +21 to +23
--model_path "${model_path}" \
--config_json "${lightx2v_path}/configs/platforms/nvidia/dist_8/hunyuan_video_t2v_480p.json" \
--prompt "A close-up shot captures a scene on a polished, light-colored granite kitchen counter, illuminated by soft natural light from an unseen window. Initially, the frame focuses on a tall, clear glass filled with golden, translucent apple juice standing next to a single, shiny red apple with a green leaf still attached to its stem. The camera moves horizontally to the right. As the shot progresses, a white ceramic plate smoothly enters the frame, revealing a fresh arrangement of about seven or eight more apples, a mix of vibrant reds and greens, piled neatly upon it. A shallow depth of field keeps the focus sharply on the fruit and glass, while the kitchen backsplash in the background remains softly blurred. The scene is in a realistic style." \

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The script references configs/platforms/nvidia/dist_8/hunyuan_video_t2v_480p.json, which does not exist because the directory was renamed to dist and the file was renamed to hunyuan_video_t2v_480p_dist8.json. This will cause a FileNotFoundError when executing the script. We should update the path to the correct config file.

Suggested change
--model_path "${model_path}" \
--config_json "${lightx2v_path}/configs/platforms/nvidia/dist_8/hunyuan_video_t2v_480p.json" \
--prompt "A close-up shot captures a scene on a polished, light-colored granite kitchen counter, illuminated by soft natural light from an unseen window. Initially, the frame focuses on a tall, clear glass filled with golden, translucent apple juice standing next to a single, shiny red apple with a green leaf still attached to its stem. The camera moves horizontally to the right. As the shot progresses, a white ceramic plate smoothly enters the frame, revealing a fresh arrangement of about seven or eight more apples, a mix of vibrant reds and greens, piled neatly upon it. A shallow depth of field keeps the focus sharply on the fruit and glass, while the kitchen backsplash in the background remains softly blurred. The scene is in a realistic style." \
--model_path "${model_path}" \
--config_json "${lightx2v_path}/configs/platforms/nvidia/dist/hunyuan_video_t2v_480p_dist8.json" \
--prompt "A close-up shot captures a scene on a polished, light-colored granite kitchen counter, illuminated by soft natural light from an unseen window. Initially, the frame focuses on a tall, clear glass filled with golden, translucent apple juice standing next to a single, shiny red apple with a green leaf still attached to its stem. The camera moves horizontally to the right. As the shot progresses, a white ceramic plate smoothly enters the frame, revealing a fresh arrangement of about seven or eight more apples, a mix of vibrant reds and greens, piled neatly upon it. A shallow depth of field keeps the focus sharply on the fruit and glass, while the kitchen backsplash in the background remains softly blurred. The scene is in a realistic style." \

Comment on lines +19 to +21
--task t2i \
--model_path "${model_path}" \
--config_json "${lightx2v_path}/configs/platforms/nvidia/dist/z_image_turbo_t2_dist2.json" \

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The script references configs/platforms/nvidia/dist/z_image_turbo_t2_dist2.json, but the added config file is named z_image_turbo_t2i_dist2.json (with an i after t2). This will cause a FileNotFoundError when executing the script. We should update the path to the correct config file.

Suggested change
--task t2i \
--model_path "${model_path}" \
--config_json "${lightx2v_path}/configs/platforms/nvidia/dist/z_image_turbo_t2_dist2.json" \
--model_path "${model_path}" \
--config_json "${lightx2v_path}/configs/platforms/nvidia/dist/z_image_turbo_t2i_dist2.json" \
--prompt 'Young Chinese woman in red Hanfu, intricate embroidery. Impeccable makeup, red floral forehead pattern. Elaborate high bun, golden phoenix headdress, red flowers, beads. Holds round folding fan with lady, trees, bird. Neon lightning-bolt lamp (⚡️), bright yellow glow, above extended left palm. Soft-lit outdoor night background, silhouetted tiered pagoda (西安大雁塔), blurred colorful distant lights.' \

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant