Files
2026-07-13 13:18:33 +08:00

141 lines
5.8 KiB
Python

# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0
# DeepSpeed Team
"""
AutoSP: one-call sequence parallelism for multimodal models.
Usage::
from deepspeed.sequence.auto_sp import auto_wrap_model_for_sp
from deepspeed.utils import groups
model, _, _, _ = deepspeed.initialize(config=ds_config, model=model, ...)
sp_group = groups._get_sequence_parallel_group()
model = auto_wrap_model_for_sp(model, process_group=sp_group)
``auto_wrap_model_for_sp`` scans the model and injects:
* :class:`~deepspeed.sequence.autosp_vit.UlyssesSPViTAttention`
for ViT encoder attention layers.
* a warning for LLM decoder attention layers: HuggingFace-style
``hidden_states`` attention is incompatible with
:class:`~deepspeed.sequence.layer.DistributedAttention`'s Q/K/V interface;
configure LLM sequence parallelism manually.
The vision-language projection layer (Phase 2) is detected and a warning is
emitted; wrap it manually with
:class:`~deepspeed.sequence.autosp_fusion.ModalityFusionSPAdapter` until
Phase 2 automation is implemented.
"""
import logging
import torch.nn as nn
from deepspeed.sequence.autosp_detector import detect_model_sp_info, _VIT_HAS_CLS_TOKEN
from deepspeed.sequence.autosp_vit import UlyssesSPViTAttention
logger = logging.getLogger(__name__)
def auto_wrap_model_for_sp(model: nn.Module, process_group) -> nn.Module:
"""Inject sequence-parallel wrappers into *model* in-place.
Scans the model's named modules and replaces recognised attention layers
with their SP-aware equivalents:
* ViT attention → :class:`UlyssesSPViTAttention`
* LLM attention → warning only (HuggingFace ``hidden_states`` interface
is incompatible with :class:`DistributedAttention`'s Q/K/V interface)
The function modifies *model* in-place **and** returns it for convenience.
Parameters
----------
model:
The multimodal model to wrap. Must be on the correct device before
calling this function.
process_group:
The sequence-parallel process group (from
``groups._get_sequence_parallel_group()``).
Returns
-------
The same *model* object with attention layers replaced.
Raises
------
ValueError
If no recognisable attention modules are found. Register the model's
attention class names in ``autosp_detector._VIT_ATTN_CLASSNAMES`` or
``_LLM_ATTN_CLASSNAMES`` to fix this.
"""
info = detect_model_sp_info(model)
if not info.vit_attn_modules and not info.llm_attn_modules:
raise ValueError("auto_wrap_model_for_sp: no recognisable attention modules found. "
"Add the model's attention class name(s) to "
"_VIT_ATTN_CLASSNAMES or _LLM_ATTN_CLASSNAMES in "
"deepspeed/sequence/autosp_detector.py and retry.")
# ------------------------------------------------------------------
# Wrap ViT encoder attention layers
# ------------------------------------------------------------------
for name, module in info.vit_attn_modules:
cls_name = type(module).__name__
# Look up whether this ViT architecture uses a CLS token; default True
# (safe fallback) for unknown classes not yet in the registry.
has_cls = _VIT_HAS_CLS_TOKEN.get(cls_name, True)
wrapped = UlyssesSPViTAttention(module, process_group, has_cls_token=has_cls)
_set_module_by_name(model, name, wrapped)
logger.debug("AutoSP: wrapped ViT attention '%s' with UlyssesSPViTAttention (has_cls_token=%s)", name, has_cls)
logger.info("AutoSP: wrapped %d ViT attention layer(s).", len(info.vit_attn_modules))
# ------------------------------------------------------------------
# LLM decoder attention layers — warn, do not auto-wrap
# ------------------------------------------------------------------
# DistributedAttention expects a Megatron-style (query, key, value)
# interface, but every class in _LLM_ATTN_CLASSNAMES uses the
# HuggingFace hidden_states interface. Wrapping them silently would
# produce incorrect behaviour at the first forward pass. Emit a
# per-layer warning so the user can configure SP manually.
for name, module in info.llm_attn_modules:
logger.warning(
"AutoSP: LLM attention '%s' (class %s) uses a HuggingFace hidden_states "
"interface that is incompatible with DistributedAttention's Q/K/V interface. "
"Skipping auto-wrap. Configure sequence parallelism for this layer manually.", name,
type(module).__name__)
if info.llm_attn_modules:
logger.info("AutoSP: found %d LLM attention layer(s); skipped wrapping (see warnings above).",
len(info.llm_attn_modules))
# ------------------------------------------------------------------
# Warn about the vision projection layer (Phase 2)
# ------------------------------------------------------------------
if info.vision_projection_module is not None:
proj_name, _ = info.vision_projection_module
logger.warning(
"AutoSP detected vision projection layer '%s'. "
"ModalityFusionSPAdapter (Phase 2) is not yet automated. "
"Wrap this layer manually with ModalityFusionSPAdapter if you "
"need correct cross-modal sequence gather/scatter.", proj_name)
return model
# ---------------------------------------------------------------------------
# Internal helpers
# ---------------------------------------------------------------------------
def _set_module_by_name(model: nn.Module, dotted_name: str, new_module: nn.Module) -> None:
"""Replace the submodule at *dotted_name* with *new_module* in-place."""
parts = dotted_name.split(".")
parent = model
for part in parts[:-1]:
parent = getattr(parent, part)
setattr(parent, parts[-1], new_module)