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

110 lines
4.8 KiB
Python

# Copyright (c) DeepSpeed Team.
# SPDX-License-Identifier: Apache-2.0
# DeepSpeed Team
"""Shared validation for AutoEP ZeRO-3 checkpoint metadata."""
from deepspeed.checkpoint.constants import (
AUTOEP_ZERO3_EXPERT_STATE_FORMAT_VERSION,
AUTOEP_ZERO3_EXPERT_STATE_FORMAT_VERSION_KEY,
AUTOEP_ZERO3_EXPERT_STATE_FORMAT_KEY,
AUTOEP_ZERO3_PARTITIONED_EXPERT_STATE_FORMAT,
)
AUTOEP_METADATA_REQUIRED_FIELDS = frozenset({
'moe_layer_id',
'module_path',
'num_experts',
'num_local_experts',
'ep_size',
'expert_key_prefix',
})
AUTOEP_ZERO3_PARTITIONED_METADATA_FIELDS = frozenset({
AUTOEP_ZERO3_EXPERT_STATE_FORMAT_VERSION_KEY,
'ep_group_name',
'ep_rank',
'expert_data_parallel_rank',
'expert_data_parallel_world_size',
'global_expert_start',
'global_expert_end',
})
def is_autoep_zero3_partitioned_entry(entry):
return (isinstance(entry, dict)
and entry.get(AUTOEP_ZERO3_EXPERT_STATE_FORMAT_KEY) == AUTOEP_ZERO3_PARTITIONED_EXPERT_STATE_FORMAT)
def validate_autoep_zero3_partitioned_metadata(autoep_metadata,
require_partitioned=True,
expected_expert_prefixes=None,
version_context="This DeepSpeed build"):
if not isinstance(autoep_metadata, list):
raise RuntimeError(f"ds_autoep_layers metadata is malformed: expected list, got "
f"{type(autoep_metadata).__name__}")
seen_layer_ids = set()
seen_prefixes = set()
partitioned_count = 0
for entry in autoep_metadata:
if not isinstance(entry, dict):
raise RuntimeError(f"ds_autoep_layers entry is malformed: expected dict, got "
f"{type(entry).__name__}")
missing = AUTOEP_METADATA_REQUIRED_FIELDS - entry.keys()
if missing:
raise RuntimeError(f"ds_autoep_layers entry is invalid: missing fields {sorted(missing)}")
layer_id = entry['moe_layer_id']
if layer_id in seen_layer_ids:
raise RuntimeError(f"ds_autoep_layers metadata has duplicate moe_layer_id: {layer_id}")
seen_layer_ids.add(layer_id)
prefix = entry['expert_key_prefix']
if prefix in seen_prefixes:
raise RuntimeError(f"ds_autoep_layers metadata has duplicate expert_key_prefix: {prefix}")
seen_prefixes.add(prefix)
if not is_autoep_zero3_partitioned_entry(entry):
continue
missing = AUTOEP_ZERO3_PARTITIONED_METADATA_FIELDS - entry.keys()
if missing:
raise RuntimeError(f"AutoEP ZeRO-3 checkpoint metadata is invalid: missing fields {sorted(missing)}")
version = entry[AUTOEP_ZERO3_EXPERT_STATE_FORMAT_VERSION_KEY]
if version != AUTOEP_ZERO3_EXPERT_STATE_FORMAT_VERSION:
raise RuntimeError("Unsupported AutoEP ZeRO-3 checkpoint format version: "
f"{version}. {version_context} supports version "
f"{AUTOEP_ZERO3_EXPERT_STATE_FORMAT_VERSION}.")
num_experts = entry['num_experts']
num_local_experts = entry['num_local_experts']
ep_size = entry['ep_size']
if num_local_experts * ep_size != num_experts:
raise RuntimeError("AutoEP ZeRO-3 checkpoint metadata is inconsistent: "
f"num_local_experts={num_local_experts}, ep_size={ep_size}, "
f"num_experts={num_experts}")
expected_start = entry['ep_rank'] * num_local_experts
expected_end = expected_start + num_local_experts
if entry['global_expert_start'] != expected_start or entry['global_expert_end'] != expected_end:
raise RuntimeError("AutoEP ZeRO-3 checkpoint metadata has inconsistent global expert range: "
f"got [{entry['global_expert_start']}, {entry['global_expert_end']}), "
f"expected [{expected_start}, {expected_end})")
if expected_expert_prefixes is not None:
module_path = entry['module_path']
if module_path not in expected_expert_prefixes:
raise RuntimeError(f"AutoEP ZeRO-3 checkpoint metadata references missing module: {module_path}")
expected_prefix = expected_expert_prefixes[module_path]
if prefix != expected_prefix:
raise RuntimeError("AutoEP ZeRO-3 checkpoint metadata has unexpected expert key prefix: "
f"got {prefix}, expected {expected_prefix}")
partitioned_count += 1
if require_partitioned and partitioned_count == 0:
raise RuntimeError("AutoEP ZeRO-3 partition-native checkpoint metadata was expected but no "
"partitioned AutoEP layer entries were found")