[diffusion][CI]: route multimodal component accuracy through run_suite (#21960)
This commit is contained in:
@@ -159,6 +159,116 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
artifact-suffix: ${{ matrix.part }}
|
artifact-suffix: ${{ matrix.part }}
|
||||||
|
|
||||||
|
multimodal-gen-component-accuracy-1-gpu:
|
||||||
|
if: |
|
||||||
|
(inputs.target_stage == 'multimodal-gen-component-accuracy-1-gpu') ||
|
||||||
|
(
|
||||||
|
!inputs.target_stage &&
|
||||||
|
((github.event_name == 'schedule' || inputs.test_parallel_dispatch == 'true') || (inputs.caller_needs_failure != 'true' && !cancelled())) &&
|
||||||
|
inputs.multimodal_gen == 'true'
|
||||||
|
)
|
||||||
|
runs-on: 1-gpu-h100
|
||||||
|
timeout-minutes: 240
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
part: [0, 1]
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
ref: ${{ inputs.pr_head_sha || inputs.git_ref || github.sha }}
|
||||||
|
|
||||||
|
- uses: ./.github/actions/check-stage-health
|
||||||
|
|
||||||
|
- uses: ./.github/actions/check-maintenance
|
||||||
|
|
||||||
|
- name: Download artifacts
|
||||||
|
if: inputs.sgl_kernel == 'true'
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
path: sgl-kernel/dist/
|
||||||
|
merge-multiple: true
|
||||||
|
pattern: wheel-python3.10-cuda12.9
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
timeout-minutes: 20
|
||||||
|
run: |
|
||||||
|
CUSTOM_BUILD_SGL_KERNEL=${{inputs.sgl_kernel}} bash scripts/ci/cuda/ci_install_dependency.sh diffusion
|
||||||
|
|
||||||
|
- name: Run diffusion component accuracy tests (1-GPU)
|
||||||
|
timeout-minutes: 240
|
||||||
|
env:
|
||||||
|
RUNAI_STREAMER_MEMORY_LIMIT: 0
|
||||||
|
CONTINUE_ON_ERROR_FLAG: ${{ inputs.continue_on_error == 'true' && '--continue-on-error' || '' }}
|
||||||
|
run: |
|
||||||
|
cd python
|
||||||
|
python3 sglang/multimodal_gen/test/run_suite.py \
|
||||||
|
--suite component-accuracy-1-gpu \
|
||||||
|
--partition-id ${{ matrix.part }} \
|
||||||
|
--total-partitions 2 \
|
||||||
|
$CONTINUE_ON_ERROR_FLAG
|
||||||
|
|
||||||
|
- uses: ./.github/actions/upload-cuda-coredumps
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
artifact-suffix: ${{ matrix.part }}
|
||||||
|
|
||||||
|
multimodal-gen-component-accuracy-2-gpu:
|
||||||
|
if: |
|
||||||
|
(inputs.target_stage == 'multimodal-gen-component-accuracy-2-gpu') ||
|
||||||
|
(
|
||||||
|
!inputs.target_stage &&
|
||||||
|
((github.event_name == 'schedule' || inputs.test_parallel_dispatch == 'true') || (inputs.caller_needs_failure != 'true' && !cancelled())) &&
|
||||||
|
inputs.multimodal_gen == 'true'
|
||||||
|
)
|
||||||
|
runs-on: 2-gpu-h100
|
||||||
|
timeout-minutes: 240
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
part: [0, 1]
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
ref: ${{ inputs.pr_head_sha || inputs.git_ref || github.sha }}
|
||||||
|
|
||||||
|
- uses: ./.github/actions/check-stage-health
|
||||||
|
|
||||||
|
- uses: ./.github/actions/check-maintenance
|
||||||
|
|
||||||
|
- name: Download artifacts
|
||||||
|
if: inputs.sgl_kernel == 'true'
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
path: sgl-kernel/dist/
|
||||||
|
merge-multiple: true
|
||||||
|
pattern: wheel-python3.10-cuda12.9
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
timeout-minutes: 20
|
||||||
|
run: |
|
||||||
|
CUSTOM_BUILD_SGL_KERNEL=${{inputs.sgl_kernel}} bash scripts/ci/cuda/ci_install_dependency.sh diffusion
|
||||||
|
|
||||||
|
- name: Run diffusion component accuracy tests (2-GPU)
|
||||||
|
timeout-minutes: 240
|
||||||
|
env:
|
||||||
|
RUNAI_STREAMER_MEMORY_LIMIT: 0
|
||||||
|
CONTINUE_ON_ERROR_FLAG: ${{ inputs.continue_on_error == 'true' && '--continue-on-error' || '' }}
|
||||||
|
run: |
|
||||||
|
cd python
|
||||||
|
python3 sglang/multimodal_gen/test/run_suite.py \
|
||||||
|
--suite component-accuracy-2-gpu \
|
||||||
|
--partition-id ${{ matrix.part }} \
|
||||||
|
--total-partitions 2 \
|
||||||
|
$CONTINUE_ON_ERROR_FLAG
|
||||||
|
|
||||||
|
- uses: ./.github/actions/upload-cuda-coredumps
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
artifact-suffix: ${{ matrix.part }}
|
||||||
|
|
||||||
multimodal-gen-test-1-b200:
|
multimodal-gen-test-1-b200:
|
||||||
if: |
|
if: |
|
||||||
(inputs.target_stage == 'multimodal-gen-test-1-b200') ||
|
(inputs.target_stage == 'multimodal-gen-test-1-b200') ||
|
||||||
|
|||||||
@@ -891,6 +891,8 @@ jobs:
|
|||||||
(
|
(
|
||||||
inputs.target_stage == 'multimodal-gen-test-1-gpu' ||
|
inputs.target_stage == 'multimodal-gen-test-1-gpu' ||
|
||||||
inputs.target_stage == 'multimodal-gen-test-2-gpu' ||
|
inputs.target_stage == 'multimodal-gen-test-2-gpu' ||
|
||||||
|
inputs.target_stage == 'multimodal-gen-component-accuracy-1-gpu' ||
|
||||||
|
inputs.target_stage == 'multimodal-gen-component-accuracy-2-gpu' ||
|
||||||
inputs.target_stage == 'multimodal-gen-test-1-b200' ||
|
inputs.target_stage == 'multimodal-gen-test-1-b200' ||
|
||||||
inputs.target_stage == 'multimodal-gen-unit-test' ||
|
inputs.target_stage == 'multimodal-gen-unit-test' ||
|
||||||
(
|
(
|
||||||
|
|||||||
@@ -56,6 +56,14 @@ SUITES = {
|
|||||||
"test_server_2_gpu_b.py",
|
"test_server_2_gpu_b.py",
|
||||||
# add new 2-gpu test files here
|
# add new 2-gpu test files here
|
||||||
],
|
],
|
||||||
|
"component-accuracy-1-gpu": [
|
||||||
|
"test_accuracy_1_gpu_a.py",
|
||||||
|
"test_accuracy_1_gpu_b.py",
|
||||||
|
],
|
||||||
|
"component-accuracy-2-gpu": [
|
||||||
|
"test_accuracy_2_gpu_a.py",
|
||||||
|
"test_accuracy_2_gpu_b.py",
|
||||||
|
],
|
||||||
"1-gpu-b200": [
|
"1-gpu-b200": [
|
||||||
"test_server_c.py",
|
"test_server_c.py",
|
||||||
],
|
],
|
||||||
@@ -78,6 +86,10 @@ suites_ascend = {
|
|||||||
|
|
||||||
SUITES.update(suites_ascend)
|
SUITES.update(suites_ascend)
|
||||||
STRICT_SUITES = {"unit"}
|
STRICT_SUITES = {"unit"}
|
||||||
|
COMPONENT_ACCURACY_SUITES = {
|
||||||
|
"component-accuracy-1-gpu",
|
||||||
|
"component-accuracy-2-gpu",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def parse_args():
|
def parse_args():
|
||||||
@@ -261,6 +273,52 @@ def run_pytest(files, filter_expr=None, exitfirst=False):
|
|||||||
return returncode
|
return returncode
|
||||||
|
|
||||||
|
|
||||||
|
def partition_test_files(files, partition_id, total_partitions):
|
||||||
|
return [
|
||||||
|
file_path
|
||||||
|
for i, file_path in enumerate(files)
|
||||||
|
if i % total_partitions == partition_id
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def run_component_accuracy_files(
|
||||||
|
files, suite: str, filter_expr=None, continue_on_error=False
|
||||||
|
):
|
||||||
|
exit_code = 0
|
||||||
|
for file_path in files:
|
||||||
|
if suite == "component-accuracy-2-gpu":
|
||||||
|
cmd = [
|
||||||
|
sys.executable,
|
||||||
|
"-m",
|
||||||
|
"torch.distributed.run",
|
||||||
|
"--nproc_per_node=2",
|
||||||
|
"-m",
|
||||||
|
"pytest",
|
||||||
|
"-s",
|
||||||
|
"-v",
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
cmd = [sys.executable, "-m", "pytest", "-s", "-v"]
|
||||||
|
|
||||||
|
if filter_expr:
|
||||||
|
cmd.extend(["-k", filter_expr])
|
||||||
|
cmd.append(file_path)
|
||||||
|
|
||||||
|
print(f"Running command: {' '.join(cmd)}")
|
||||||
|
file_exit_code = subprocess.call(cmd)
|
||||||
|
if file_exit_code == 5:
|
||||||
|
print(
|
||||||
|
"No tests collected (exit code 5). This is expected when filters "
|
||||||
|
"deselect all tests in a file. Treating as success."
|
||||||
|
)
|
||||||
|
file_exit_code = 0
|
||||||
|
if file_exit_code != 0 and exit_code == 0:
|
||||||
|
exit_code = file_exit_code
|
||||||
|
if file_exit_code != 0 and not continue_on_error:
|
||||||
|
return file_exit_code
|
||||||
|
return exit_code
|
||||||
|
|
||||||
|
|
||||||
def _is_in_ci() -> bool:
|
def _is_in_ci() -> bool:
|
||||||
return os.environ.get("SGLANG_IS_IN_CI", "").lower() in ("1", "true", "yes", "on")
|
return os.environ.get("SGLANG_IS_IN_CI", "").lower() in ("1", "true", "yes", "on")
|
||||||
|
|
||||||
@@ -314,6 +372,49 @@ def main():
|
|||||||
print(f"No valid test files found for suite '{args.suite}'.")
|
print(f"No valid test files found for suite '{args.suite}'.")
|
||||||
sys.exit(1 if args.suite in STRICT_SUITES else 0)
|
sys.exit(1 if args.suite in STRICT_SUITES else 0)
|
||||||
|
|
||||||
|
if args.suite in COMPONENT_ACCURACY_SUITES:
|
||||||
|
my_files = partition_test_files(
|
||||||
|
suite_files_abs, args.partition_id, args.total_partitions
|
||||||
|
)
|
||||||
|
partition_info = (
|
||||||
|
f"{args.partition_id + 1}/{args.total_partitions} "
|
||||||
|
f"(0-based id={args.partition_id})"
|
||||||
|
)
|
||||||
|
headers = ["Suite", "Partition"]
|
||||||
|
rows = [[args.suite, partition_info]]
|
||||||
|
msg = tabulate.tabulate(rows, headers=headers, tablefmt="psql") + "\n"
|
||||||
|
msg += f"✅ Enabled {len(my_files)} file(s):\n"
|
||||||
|
for file_path in my_files:
|
||||||
|
msg += f" - {file_path}\n"
|
||||||
|
print(msg, flush=True)
|
||||||
|
print(
|
||||||
|
f"Suite: {args.suite} | Partition: {args.partition_id}/{args.total_partitions}"
|
||||||
|
)
|
||||||
|
print(f"Selected {len(suite_files_abs)} files:")
|
||||||
|
for f in suite_files_abs:
|
||||||
|
print(f" - {os.path.basename(f)}")
|
||||||
|
|
||||||
|
if not my_files:
|
||||||
|
print("No files assigned to this partition. Exiting success.")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
print(f"Running {len(my_files)} files in this shard: {', '.join(my_files)}")
|
||||||
|
|
||||||
|
exit_code = run_component_accuracy_files(
|
||||||
|
my_files,
|
||||||
|
suite=args.suite,
|
||||||
|
filter_expr=args.filter,
|
||||||
|
continue_on_error=args.continue_on_error,
|
||||||
|
)
|
||||||
|
|
||||||
|
msg = "\n" + tabulate.tabulate(rows, headers=headers, tablefmt="psql") + "\n"
|
||||||
|
msg += f"✅ Executed {len(my_files)} file(s):\n"
|
||||||
|
for file_path in my_files:
|
||||||
|
msg += f" - {file_path}\n"
|
||||||
|
print(msg, flush=True)
|
||||||
|
|
||||||
|
sys.exit(exit_code)
|
||||||
|
|
||||||
# 3. collect all test items and partition by items (not files)
|
# 3. collect all test items and partition by items (not files)
|
||||||
all_test_items = collect_test_items(suite_files_abs, filter_expr=args.filter)
|
all_test_items = collect_test_items(suite_files_abs, filter_expr=args.filter)
|
||||||
|
|
||||||
@@ -352,7 +453,11 @@ def main():
|
|||||||
|
|
||||||
# 4. execute with the specific test items
|
# 4. execute with the specific test items
|
||||||
# Fast-fail: stop on first failure unless --continue-on-error is set
|
# Fast-fail: stop on first failure unless --continue-on-error is set
|
||||||
exit_code = run_pytest(my_items, exitfirst=not args.continue_on_error)
|
exit_code = run_pytest(
|
||||||
|
my_items,
|
||||||
|
filter_expr=args.filter,
|
||||||
|
exitfirst=not args.continue_on_error,
|
||||||
|
)
|
||||||
|
|
||||||
# Print tests again at the end for visibility
|
# Print tests again at the end for visibility
|
||||||
msg = "\n" + tabulate.tabulate(rows, headers=headers, tablefmt="psql") + "\n"
|
msg = "\n" + tabulate.tabulate(rows, headers=headers, tablefmt="psql") + "\n"
|
||||||
|
|||||||
@@ -73,6 +73,14 @@ SKIP_COMPONENTS: Dict[str, Dict[ComponentType, ComponentSkip]] = {
|
|||||||
"HF reference transformer cannot be materialized from the video_dit repo layout"
|
"HF reference transformer cannot be materialized from the video_dit repo layout"
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
"ltx_2.3_one_stage_ti2v": {
|
||||||
|
ComponentType.VAE: ComponentSkip(
|
||||||
|
"LTX-2.3 VAE component diverges from the HF reference after local overlay materialization; weight transfer matched 96/176 (54.55%), below the minimum threshold for trustworthy comparison"
|
||||||
|
),
|
||||||
|
ComponentType.TRANSFORMER: ComponentSkip(
|
||||||
|
"LTX-2.3 transformer component does not match the HF reference architecture after local overlay materialization; scale_shift_table parameters load as [9, ...] in the checkpoint but [6, ...] in the reference model"
|
||||||
|
),
|
||||||
|
},
|
||||||
"qwen_image_t2i_cache_dit_enabled": {
|
"qwen_image_t2i_cache_dit_enabled": {
|
||||||
ComponentType.VAE: ComponentSkip(
|
ComponentType.VAE: ComponentSkip(
|
||||||
"Representative VAE accuracy is already covered by qwen_image_t2i for the same source component and topology"
|
"Representative VAE accuracy is already covered by qwen_image_t2i for the same source component and topology"
|
||||||
@@ -353,6 +361,11 @@ SKIP_COMPONENTS: Dict[str, Dict[ComponentType, ComponentSkip]] = {
|
|||||||
"2-GPU FLUX.2 transformer diverges strongly from Diffusers baseline (CosSim ~0.54) despite full weight transfer"
|
"2-GPU FLUX.2 transformer diverges strongly from Diffusers baseline (CosSim ~0.54) despite full weight transfer"
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
"ltx_2_two_stage_t2v": {
|
||||||
|
ComponentType.TRANSFORMER: ComponentSkip(
|
||||||
|
"Transformer output shape mismatch after 100% matched weight transfer: SGL [1, 128, 4, 16, 16] vs Diffusers [1, 1024, 128]"
|
||||||
|
)
|
||||||
|
},
|
||||||
"hunyuan3d_shape_gen": {
|
"hunyuan3d_shape_gen": {
|
||||||
ComponentType.VAE: ComponentSkip(
|
ComponentType.VAE: ComponentSkip(
|
||||||
"HF config cannot be parsed as valid JSON for component reference loading"
|
"HF config cannot be parsed as valid JSON for component reference loading"
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ DEFAULT_TEXT_SEQ_LEN = 64
|
|||||||
DEFAULT_TOKEN_LAYOUT_SIZE = 32
|
DEFAULT_TOKEN_LAYOUT_SIZE = 32
|
||||||
REDUCED_TOKEN_LAYOUT_SIZE = 16
|
REDUCED_TOKEN_LAYOUT_SIZE = 16
|
||||||
DEFAULT_VIDEO_FRAME_COUNT = 4
|
DEFAULT_VIDEO_FRAME_COUNT = 4
|
||||||
|
DEFAULT_AUDIO_FRAME_COUNT = 16
|
||||||
DEFAULT_IMAGE_TOKEN_COUNT = 257
|
DEFAULT_IMAGE_TOKEN_COUNT = 257
|
||||||
ALIAS_ROTARY_TEXT_PAD_MULTIPLE = 32
|
ALIAS_ROTARY_TEXT_PAD_MULTIPLE = 32
|
||||||
DEFAULT_TRANSFORMER_IN_CHANNELS = 16
|
DEFAULT_TRANSFORMER_IN_CHANNELS = 16
|
||||||
@@ -210,6 +211,13 @@ def _build_transformer_hook_inputs(
|
|||||||
|
|
||||||
rng = _DeterministicRNG()
|
rng = _DeterministicRNG()
|
||||||
layout = _infer_transformer_layout(param_names)
|
layout = _infer_transformer_layout(param_names)
|
||||||
|
requires_audio_stream_inputs = (
|
||||||
|
"audio_hidden_states" in param_names
|
||||||
|
and "audio_encoder_hidden_states" in param_names
|
||||||
|
)
|
||||||
|
requires_audio_video_shape_inputs = requires_audio_stream_inputs and all(
|
||||||
|
key in param_names for key in ("num_frames", "height", "width")
|
||||||
|
)
|
||||||
in_channels = _read_config_value(
|
in_channels = _read_config_value(
|
||||||
model,
|
model,
|
||||||
[
|
[
|
||||||
@@ -238,6 +246,16 @@ def _build_transformer_hook_inputs(
|
|||||||
],
|
],
|
||||||
default=DEFAULT_TRANSFORMER_TEXT_CHANNELS,
|
default=DEFAULT_TRANSFORMER_TEXT_CHANNELS,
|
||||||
)
|
)
|
||||||
|
audio_in_channels = _read_config_value(
|
||||||
|
model,
|
||||||
|
[
|
||||||
|
"arch_config.audio_in_channels",
|
||||||
|
"audio_in_channels",
|
||||||
|
"arch_config.audio_out_channels",
|
||||||
|
"audio_out_channels",
|
||||||
|
],
|
||||||
|
default=in_channels,
|
||||||
|
)
|
||||||
pooled_channels = _read_config_value(
|
pooled_channels = _read_config_value(
|
||||||
model,
|
model,
|
||||||
[
|
[
|
||||||
@@ -256,7 +274,21 @@ def _build_transformer_hook_inputs(
|
|||||||
default=I2V_IMAGE_DIM,
|
default=I2V_IMAGE_DIM,
|
||||||
)
|
)
|
||||||
|
|
||||||
if layout == "token_shapes":
|
if requires_audio_video_shape_inputs:
|
||||||
|
patch_size = getattr(model, "patch_size", None)
|
||||||
|
if not (
|
||||||
|
isinstance(patch_size, tuple)
|
||||||
|
and len(patch_size) == 3
|
||||||
|
and all(isinstance(dim, int) and dim > 0 for dim in patch_size)
|
||||||
|
):
|
||||||
|
patch_size = (1, 2, 2)
|
||||||
|
patch_t, patch_h, patch_w = patch_size
|
||||||
|
num_frames = DEFAULT_VIDEO_FRAME_COUNT * patch_t
|
||||||
|
height = REDUCED_TOKEN_LAYOUT_SIZE * patch_h
|
||||||
|
width = REDUCED_TOKEN_LAYOUT_SIZE * patch_w
|
||||||
|
seq_len = (num_frames // patch_t) * (height // patch_h) * (width // patch_w)
|
||||||
|
hidden_states = rng.randn((1, seq_len, in_channels), device, torch.bfloat16)
|
||||||
|
elif layout == "token_shapes":
|
||||||
height, width = DEFAULT_TOKEN_LAYOUT_SIZE, DEFAULT_TOKEN_LAYOUT_SIZE
|
height, width = DEFAULT_TOKEN_LAYOUT_SIZE, DEFAULT_TOKEN_LAYOUT_SIZE
|
||||||
seq_len = (height // 2) * (width // 2)
|
seq_len = (height // 2) * (width // 2)
|
||||||
hidden_states = rng.randn((1, seq_len, in_channels), device, torch.bfloat16)
|
hidden_states = rng.randn((1, seq_len, in_channels), device, torch.bfloat16)
|
||||||
@@ -307,6 +339,24 @@ def _build_transformer_hook_inputs(
|
|||||||
"guidance": torch.tensor([1.0], device=device, dtype=torch.bfloat16),
|
"guidance": torch.tensor([1.0], device=device, dtype=torch.bfloat16),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if requires_audio_stream_inputs:
|
||||||
|
inputs["audio_hidden_states"] = rng.randn(
|
||||||
|
(1, DEFAULT_AUDIO_FRAME_COUNT, audio_in_channels),
|
||||||
|
device,
|
||||||
|
torch.bfloat16,
|
||||||
|
)
|
||||||
|
inputs["audio_encoder_hidden_states"] = rng.randn(
|
||||||
|
(1, DEFAULT_TEXT_SEQ_LEN, text_channels),
|
||||||
|
device,
|
||||||
|
torch.bfloat16,
|
||||||
|
)
|
||||||
|
inputs["audio_timestep"] = inputs["timestep"].clone()
|
||||||
|
inputs["audio_num_frames"] = DEFAULT_AUDIO_FRAME_COUNT
|
||||||
|
if requires_audio_video_shape_inputs:
|
||||||
|
inputs["num_frames"] = num_frames
|
||||||
|
inputs["height"] = height
|
||||||
|
inputs["width"] = width
|
||||||
|
|
||||||
if "pooled_projections" in param_names:
|
if "pooled_projections" in param_names:
|
||||||
inputs["pooled_projections"] = rng.randn(
|
inputs["pooled_projections"] = rng.randn(
|
||||||
(1, pooled_channels), device, torch.bfloat16
|
(1, pooled_channels), device, torch.bfloat16
|
||||||
@@ -320,6 +370,10 @@ def _build_transformer_hook_inputs(
|
|||||||
)
|
)
|
||||||
inputs["encoder_attention_mask"] = attention_mask
|
inputs["encoder_attention_mask"] = attention_mask
|
||||||
inputs["encoder_hidden_states_mask"] = attention_mask
|
inputs["encoder_hidden_states_mask"] = attention_mask
|
||||||
|
if "audio_encoder_attention_mask" in param_names:
|
||||||
|
inputs["audio_encoder_attention_mask"] = torch.ones(
|
||||||
|
1, DEFAULT_TEXT_SEQ_LEN, device=device, dtype=torch.bool
|
||||||
|
)
|
||||||
if "encoder_hidden_states_image" in param_names and _supports_image_conditioning(
|
if "encoder_hidden_states_image" in param_names and _supports_image_conditioning(
|
||||||
model
|
model
|
||||||
):
|
):
|
||||||
@@ -471,8 +525,16 @@ def _prepare_transformer_hook_call(
|
|||||||
"txt_seq_lens",
|
"txt_seq_lens",
|
||||||
"freqs_cis",
|
"freqs_cis",
|
||||||
"additional_t_cond",
|
"additional_t_cond",
|
||||||
|
"audio_hidden_states",
|
||||||
|
"audio_encoder_hidden_states",
|
||||||
|
"audio_timestep",
|
||||||
"encoder_attention_mask",
|
"encoder_attention_mask",
|
||||||
"encoder_hidden_states_mask",
|
"encoder_hidden_states_mask",
|
||||||
|
"audio_encoder_attention_mask",
|
||||||
|
"num_frames",
|
||||||
|
"height",
|
||||||
|
"width",
|
||||||
|
"audio_num_frames",
|
||||||
):
|
):
|
||||||
if key in param_names and key in inputs:
|
if key in param_names and key in inputs:
|
||||||
kwargs[key] = inputs[key]
|
kwargs[key] = inputs[key]
|
||||||
@@ -491,6 +553,17 @@ def _prepare_transformer_reference_call(module: nn.Module, inputs: Inputs) -> Ho
|
|||||||
return _prepare_transformer_hook_call(module, inputs, side="reference")
|
return _prepare_transformer_hook_call(module, inputs, side="reference")
|
||||||
|
|
||||||
|
|
||||||
|
def _normalize_transformer_reference_output(output: Any) -> torch.Tensor:
|
||||||
|
sample = getattr(output, "sample", None)
|
||||||
|
if (
|
||||||
|
isinstance(sample, (list, tuple))
|
||||||
|
and sample
|
||||||
|
and all(isinstance(item, torch.Tensor) for item in sample)
|
||||||
|
):
|
||||||
|
return torch.stack(list(sample), dim=0)
|
||||||
|
return extract_output_tensor(output)
|
||||||
|
|
||||||
|
|
||||||
class _VAEDecodeModule(nn.Module):
|
class _VAEDecodeModule(nn.Module):
|
||||||
def __init__(self, vae: nn.Module):
|
def __init__(self, vae: nn.Module):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
@@ -562,6 +635,7 @@ TRANSFORMER_NATIVE_PROFILE = NativeHookProfile(
|
|||||||
build_inputs=_build_transformer_hook_inputs,
|
build_inputs=_build_transformer_hook_inputs,
|
||||||
prepare_sglang_call=_prepare_transformer_sglang_call,
|
prepare_sglang_call=_prepare_transformer_sglang_call,
|
||||||
prepare_reference_call=_prepare_transformer_reference_call,
|
prepare_reference_call=_prepare_transformer_reference_call,
|
||||||
|
normalize_reference_output=_normalize_transformer_reference_output,
|
||||||
)
|
)
|
||||||
|
|
||||||
VAE_NATIVE_PROFILE = NativeHookProfile(
|
VAE_NATIVE_PROFILE = NativeHookProfile(
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
from contextlib import nullcontext
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Any, Dict, List, Optional, Tuple
|
from typing import Any, Dict, List, Optional, Tuple
|
||||||
|
|
||||||
@@ -19,8 +20,12 @@ from sglang.multimodal_gen.runtime.distributed.parallel_state import (
|
|||||||
model_parallel_is_initialized,
|
model_parallel_is_initialized,
|
||||||
)
|
)
|
||||||
from sglang.multimodal_gen.runtime.layers.utils import get_group_rank, get_group_size
|
from sglang.multimodal_gen.runtime.layers.utils import get_group_rank, get_group_size
|
||||||
from sglang.multimodal_gen.runtime.server_args import ServerArgs
|
from sglang.multimodal_gen.runtime.server_args import ServerArgs, get_global_server_args
|
||||||
from sglang.multimodal_gen.runtime.utils.hf_diffusers_utils import maybe_download_model
|
from sglang.multimodal_gen.runtime.utils.hf_diffusers_utils import maybe_download_model
|
||||||
|
from sglang.multimodal_gen.runtime.utils.model_overlay import (
|
||||||
|
load_overlay_manifest_if_present,
|
||||||
|
resolve_model_overlay_target,
|
||||||
|
)
|
||||||
from sglang.multimodal_gen.test.server.accuracy_config import (
|
from sglang.multimodal_gen.test.server.accuracy_config import (
|
||||||
DEFAULT_TEXT_ENCODER_VOCAB_SIZE,
|
DEFAULT_TEXT_ENCODER_VOCAB_SIZE,
|
||||||
I2V_TEXT_ENCODER_DIM,
|
I2V_TEXT_ENCODER_DIM,
|
||||||
@@ -32,27 +37,6 @@ from sglang.multimodal_gen.test.server.accuracy_config import (
|
|||||||
get_threshold,
|
get_threshold,
|
||||||
)
|
)
|
||||||
|
|
||||||
STAGED_1GPU_NATIVE_CASE_IDS = {
|
|
||||||
"flux_2_image_t2i",
|
|
||||||
"qwen_image_layered_i2i",
|
|
||||||
"flux_2_image_t2i_upscaling_4x",
|
|
||||||
"flux_2_ti2i",
|
|
||||||
"flux_2_t2i_customized_vae_path",
|
|
||||||
"flux_2_ti2i_multi_image_cache_dit",
|
|
||||||
}
|
|
||||||
|
|
||||||
# These case allowlists are accuracy-runner policy. They select the few 1-GPU
|
|
||||||
# cases that need sequential SGLang/reference execution to stay within memory
|
|
||||||
# limits during CI and local correctness runs.
|
|
||||||
STAGED_1GPU_TEXT_ENCODER_CASE_IDS = {
|
|
||||||
"flux_2_image_t2i",
|
|
||||||
"flux_2_image_t2i_upscaling_4x",
|
|
||||||
"mova_360p_1gpu",
|
|
||||||
"flux_2_ti2i",
|
|
||||||
"flux_2_t2i_customized_vae_path",
|
|
||||||
"flux_2_ti2i_multi_image_cache_dit",
|
|
||||||
}
|
|
||||||
|
|
||||||
SOURCE_PREFIXES = (
|
SOURCE_PREFIXES = (
|
||||||
"module.",
|
"module.",
|
||||||
"model.",
|
"model.",
|
||||||
@@ -81,9 +65,7 @@ class ComponentSelection:
|
|||||||
base_model_id: str
|
base_model_id: str
|
||||||
base_model_root: str
|
base_model_root: str
|
||||||
component_paths: Dict[str, str]
|
component_paths: Dict[str, str]
|
||||||
source_root: str
|
|
||||||
source_path: str
|
source_path: str
|
||||||
source_subfolder: str
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
@@ -153,7 +135,7 @@ def _resolve_component_subfolder(
|
|||||||
|
|
||||||
def resolve_component_path(
|
def resolve_component_path(
|
||||||
local_root: str, component: ComponentType, model_index_keys: Tuple[str, ...]
|
local_root: str, component: ComponentType, model_index_keys: Tuple[str, ...]
|
||||||
) -> Tuple[str, str]:
|
) -> str:
|
||||||
model_index_path = os.path.join(local_root, "model_index.json")
|
model_index_path = os.path.join(local_root, "model_index.json")
|
||||||
model_index = read_json_file(model_index_path)
|
model_index = read_json_file(model_index_path)
|
||||||
|
|
||||||
@@ -169,13 +151,13 @@ def resolve_component_path(
|
|||||||
candidate
|
candidate
|
||||||
):
|
):
|
||||||
continue
|
continue
|
||||||
return candidate, subfolder
|
return candidate
|
||||||
|
|
||||||
if has_component_files(local_root):
|
if has_component_files(local_root):
|
||||||
if component != ComponentType.TEXT_ENCODER or is_text_encoder_config(
|
if component != ComponentType.TEXT_ENCODER or is_text_encoder_config(
|
||||||
local_root
|
local_root
|
||||||
):
|
):
|
||||||
return local_root, ""
|
return local_root
|
||||||
|
|
||||||
raise FileNotFoundError(
|
raise FileNotFoundError(
|
||||||
f"Could not resolve {component.value} from model_index.json under {local_root}"
|
f"Could not resolve {component.value} from model_index.json under {local_root}"
|
||||||
@@ -230,37 +212,48 @@ def select_component_source(
|
|||||||
model_index_keys: Tuple[str, ...],
|
model_index_keys: Tuple[str, ...],
|
||||||
) -> ComponentSelection:
|
) -> ComponentSelection:
|
||||||
component_paths = extract_component_path_overrides(extra_args)
|
component_paths = extract_component_path_overrides(extra_args)
|
||||||
base_model_root = maybe_download_model(model_id)
|
force_diffusers_model = resolve_model_overlay_target(model_id) is not None or (
|
||||||
|
os.path.exists(model_id)
|
||||||
|
and load_overlay_manifest_if_present(model_id) is not None
|
||||||
|
)
|
||||||
|
base_model_root = maybe_download_model(
|
||||||
|
model_id, force_diffusers_model=force_diffusers_model
|
||||||
|
)
|
||||||
search_keys = [component.value]
|
search_keys = [component.value]
|
||||||
for key in model_index_keys:
|
for key in model_index_keys:
|
||||||
if key not in search_keys:
|
if key not in search_keys:
|
||||||
search_keys.append(key)
|
search_keys.append(key)
|
||||||
|
|
||||||
source_root = base_model_root
|
|
||||||
component_key = component.value
|
|
||||||
for key in search_keys:
|
for key in search_keys:
|
||||||
override_path = component_paths.get(key)
|
override_path = component_paths.get(key)
|
||||||
if override_path:
|
if override_path is None:
|
||||||
source_root = maybe_download_model(override_path)
|
continue
|
||||||
component_key = key
|
assert has_component_files(override_path), (
|
||||||
break
|
f"Component override for {component.value} must point directly to a "
|
||||||
|
f"component directory: {override_path}"
|
||||||
|
)
|
||||||
|
if component == ComponentType.TEXT_ENCODER:
|
||||||
|
assert is_text_encoder_config(override_path), (
|
||||||
|
f"Text encoder override must point to a text encoder directory: "
|
||||||
|
f"{override_path}"
|
||||||
|
)
|
||||||
|
return ComponentSelection(
|
||||||
|
base_model_id=model_id,
|
||||||
|
base_model_root=base_model_root,
|
||||||
|
component_paths=component_paths,
|
||||||
|
source_path=override_path,
|
||||||
|
)
|
||||||
|
|
||||||
ordered_keys = [component_key]
|
source_path = resolve_component_path(
|
||||||
for key in search_keys:
|
base_model_root,
|
||||||
if key not in ordered_keys:
|
|
||||||
ordered_keys.append(key)
|
|
||||||
source_path, source_subfolder = resolve_component_path(
|
|
||||||
source_root,
|
|
||||||
component,
|
component,
|
||||||
tuple(ordered_keys),
|
tuple(search_keys),
|
||||||
)
|
)
|
||||||
return ComponentSelection(
|
return ComponentSelection(
|
||||||
base_model_id=model_id,
|
base_model_id=model_id,
|
||||||
base_model_root=base_model_root,
|
base_model_root=base_model_root,
|
||||||
component_paths=component_paths,
|
component_paths=component_paths,
|
||||||
source_root=source_root,
|
|
||||||
source_path=source_path,
|
source_path=source_path,
|
||||||
source_subfolder=source_subfolder,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -680,16 +673,6 @@ def run_text_encoder_accuracy_pair(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _should_stage_case(case: Any, component: ComponentType, num_gpus: int) -> bool:
|
|
||||||
if num_gpus == 2:
|
|
||||||
return True
|
|
||||||
if num_gpus != 1:
|
|
||||||
return False
|
|
||||||
if component == ComponentType.TEXT_ENCODER:
|
|
||||||
return case.id in STAGED_1GPU_TEXT_ENCODER_CASE_IDS
|
|
||||||
return case.id in STAGED_1GPU_NATIVE_CASE_IDS
|
|
||||||
|
|
||||||
|
|
||||||
def _run_single_text_encoder_forward(
|
def _run_single_text_encoder_forward(
|
||||||
model: nn.Module, input_ids: torch.Tensor, attention_mask: torch.Tensor
|
model: nn.Module, input_ids: torch.Tensor, attention_mask: torch.Tensor
|
||||||
) -> torch.Tensor:
|
) -> torch.Tensor:
|
||||||
@@ -724,26 +707,55 @@ def _run_staged_native_component_accuracy_case(
|
|||||||
component,
|
component,
|
||||||
library,
|
library,
|
||||||
num_gpus,
|
num_gpus,
|
||||||
|
materialize_sgl_on_device=(component != ComponentType.TRANSFORMER),
|
||||||
materialize_ref_on_device=False,
|
materialize_ref_on_device=False,
|
||||||
)
|
)
|
||||||
|
if component == ComponentType.TRANSFORMER:
|
||||||
|
sgl = sgl.to(device=device, dtype=torch.bfloat16).eval()
|
||||||
profile = resolve_component_native_profile(component)
|
profile = resolve_component_native_profile(component)
|
||||||
inputs = profile.build_inputs(case, sgl, device, ref)
|
inputs = profile.build_inputs(case, sgl, device, ref)
|
||||||
|
runtime_server_args = get_global_server_args()
|
||||||
|
use_transformer_autocast = (
|
||||||
|
component == ComponentType.TRANSFORMER
|
||||||
|
and not runtime_server_args.disable_autocast
|
||||||
|
and torch.device(device).type != "cpu"
|
||||||
|
)
|
||||||
|
|
||||||
sgl_call = profile.prepare_sglang_call(sgl, inputs)
|
sgl_call = profile.prepare_sglang_call(sgl, inputs)
|
||||||
with torch.no_grad():
|
sgl_autocast = (
|
||||||
|
torch.autocast(
|
||||||
|
device_type=torch.device(device).type,
|
||||||
|
dtype=torch.bfloat16,
|
||||||
|
enabled=True,
|
||||||
|
)
|
||||||
|
if use_transformer_autocast
|
||||||
|
else nullcontext()
|
||||||
|
)
|
||||||
|
with torch.no_grad(), sgl_autocast:
|
||||||
sgl_raw = engine_cls._execute_with_native_hook(sgl_call)
|
sgl_raw = engine_cls._execute_with_native_hook(sgl_call)
|
||||||
sgl_out = profile.normalize_sglang_output(sgl_raw)
|
sgl_out = profile.normalize_sglang_output(sgl_raw)
|
||||||
sgl_out = engine_cls._apply_output_transforms(sgl_out, sgl_call).detach().cpu()
|
sgl_out = engine_cls._apply_output_transforms(sgl_out, sgl_call).detach().cpu()
|
||||||
|
|
||||||
del sgl_call
|
del sgl_call
|
||||||
del sgl_raw
|
del sgl_raw
|
||||||
|
if component == ComponentType.TRANSFORMER and num_gpus == 1:
|
||||||
|
engine_cls.prepare_component_for_release(sgl)
|
||||||
del sgl
|
del sgl
|
||||||
sgl = None
|
sgl = None
|
||||||
engine_cls.clear_memory()
|
engine_cls.clear_memory()
|
||||||
|
|
||||||
ref = ref.to(device=device, dtype=torch.bfloat16).eval()
|
ref = ref.to(device=device, dtype=torch.bfloat16).eval()
|
||||||
ref_call = profile.prepare_reference_call(ref, inputs)
|
ref_call = profile.prepare_reference_call(ref, inputs)
|
||||||
with torch.no_grad():
|
ref_autocast = (
|
||||||
|
torch.autocast(
|
||||||
|
device_type=torch.device(device).type,
|
||||||
|
dtype=torch.bfloat16,
|
||||||
|
enabled=True,
|
||||||
|
)
|
||||||
|
if use_transformer_autocast
|
||||||
|
else nullcontext()
|
||||||
|
)
|
||||||
|
with torch.no_grad(), ref_autocast:
|
||||||
ref_raw = engine_cls._execute_with_native_hook(ref_call)
|
ref_raw = engine_cls._execute_with_native_hook(ref_call)
|
||||||
ref_out = profile.normalize_reference_output(ref_raw)
|
ref_out = profile.normalize_reference_output(ref_raw)
|
||||||
ref_out = engine_cls._apply_output_transforms(ref_out, ref_call).detach().cpu()
|
ref_out = engine_cls._apply_output_transforms(ref_out, ref_call).detach().cpu()
|
||||||
@@ -758,6 +770,8 @@ def _run_staged_native_component_accuracy_case(
|
|||||||
)
|
)
|
||||||
finally:
|
finally:
|
||||||
if sgl is not None:
|
if sgl is not None:
|
||||||
|
if component == ComponentType.TRANSFORMER and num_gpus == 1:
|
||||||
|
engine_cls.prepare_component_for_release(sgl)
|
||||||
del sgl
|
del sgl
|
||||||
if ref is not None:
|
if ref is not None:
|
||||||
del ref
|
del ref
|
||||||
@@ -823,58 +837,10 @@ def run_native_component_accuracy_case(
|
|||||||
library: str,
|
library: str,
|
||||||
num_gpus: int,
|
num_gpus: int,
|
||||||
) -> None:
|
) -> None:
|
||||||
if _should_stage_case(case, component, num_gpus):
|
|
||||||
_run_staged_native_component_accuracy_case(
|
_run_staged_native_component_accuracy_case(
|
||||||
engine_cls, case, component, library, num_gpus
|
engine_cls, case, component, library, num_gpus
|
||||||
)
|
)
|
||||||
return
|
|
||||||
engine_cls.clear_memory()
|
|
||||||
sgl = None
|
|
||||||
ref = None
|
|
||||||
try:
|
|
||||||
sgl, ref, device = engine_cls.load_component_pair(
|
|
||||||
case, component, library, num_gpus
|
|
||||||
)
|
|
||||||
sgl_out, ref_out = engine_cls.run_component_pair_native(
|
|
||||||
case, component, sgl, ref, device
|
|
||||||
)
|
|
||||||
engine_cls.check_accuracy(
|
|
||||||
sgl_out,
|
|
||||||
ref_out,
|
|
||||||
f"{case.id}_{component.value}",
|
|
||||||
get_threshold(case.id, component),
|
|
||||||
)
|
|
||||||
finally:
|
|
||||||
if sgl is not None:
|
|
||||||
del sgl
|
|
||||||
if ref is not None:
|
|
||||||
del ref
|
|
||||||
engine_cls.reset_parallel_runtime()
|
|
||||||
engine_cls.clear_memory()
|
|
||||||
|
|
||||||
|
|
||||||
def run_text_encoder_accuracy_case(engine_cls: Any, case: Any, num_gpus: int) -> None:
|
def run_text_encoder_accuracy_case(engine_cls: Any, case: Any, num_gpus: int) -> None:
|
||||||
if _should_stage_case(case, ComponentType.TEXT_ENCODER, num_gpus):
|
|
||||||
_run_staged_text_encoder_accuracy_case(engine_cls, case, num_gpus)
|
_run_staged_text_encoder_accuracy_case(engine_cls, case, num_gpus)
|
||||||
return
|
|
||||||
engine_cls.clear_memory()
|
|
||||||
sgl = None
|
|
||||||
ref = None
|
|
||||||
try:
|
|
||||||
sgl, ref, _device = engine_cls.load_component_pair(
|
|
||||||
case, ComponentType.TEXT_ENCODER, "transformers", num_gpus
|
|
||||||
)
|
|
||||||
sgl_out, ref_out = run_text_encoder_accuracy_pair(sgl, ref)
|
|
||||||
engine_cls.check_accuracy(
|
|
||||||
sgl_out,
|
|
||||||
ref_out,
|
|
||||||
f"{case.id}_encoder",
|
|
||||||
get_threshold(case.id, ComponentType.TEXT_ENCODER),
|
|
||||||
)
|
|
||||||
finally:
|
|
||||||
if sgl is not None:
|
|
||||||
del sgl
|
|
||||||
if ref is not None:
|
|
||||||
del ref
|
|
||||||
engine_cls.reset_parallel_runtime()
|
|
||||||
engine_cls.clear_memory()
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ except ImportError:
|
|||||||
|
|
||||||
import sglang.multimodal_gen.runtime.managers.forward_context as fc_mod
|
import sglang.multimodal_gen.runtime.managers.forward_context as fc_mod
|
||||||
from sglang.multimodal_gen.runtime.distributed.parallel_state import (
|
from sglang.multimodal_gen.runtime.distributed.parallel_state import (
|
||||||
|
cleanup_dist_env_and_memory,
|
||||||
destroy_model_parallel,
|
destroy_model_parallel,
|
||||||
get_local_torch_device,
|
get_local_torch_device,
|
||||||
get_tensor_model_parallel_rank,
|
get_tensor_model_parallel_rank,
|
||||||
@@ -149,13 +150,34 @@ def _load_wan_reference_vae(comp_path: str, pipeline_config) -> nn.Module:
|
|||||||
return vae
|
return vae
|
||||||
|
|
||||||
|
|
||||||
|
def _load_reference_component_from_local_safetensors(
|
||||||
|
component_cls: type[nn.Module],
|
||||||
|
comp_path: str,
|
||||||
|
component_name: str,
|
||||||
|
) -> nn.Module:
|
||||||
|
config = component_cls.load_config(comp_path)
|
||||||
|
component = component_cls.from_config(config)
|
||||||
|
missing_keys, unexpected_keys = load_checkpoint_weights(component, comp_path)
|
||||||
|
if missing_keys:
|
||||||
|
logger.warning(
|
||||||
|
"Reference %s missing keys from local safetensors: %s",
|
||||||
|
component_name,
|
||||||
|
missing_keys,
|
||||||
|
)
|
||||||
|
if unexpected_keys:
|
||||||
|
logger.warning(
|
||||||
|
"Reference %s unexpected keys from local safetensors: %s",
|
||||||
|
component_name,
|
||||||
|
unexpected_keys,
|
||||||
|
)
|
||||||
|
return component
|
||||||
|
|
||||||
|
|
||||||
def _load_reference_component(
|
def _load_reference_component(
|
||||||
comp_path: str,
|
comp_path: str,
|
||||||
source_root: str,
|
|
||||||
component: ComponentType,
|
component: ComponentType,
|
||||||
hub_id: str,
|
hub_id: str,
|
||||||
pipeline_config,
|
pipeline_config,
|
||||||
subfolder: str,
|
|
||||||
) -> nn.Module:
|
) -> nn.Module:
|
||||||
# WAN VAE does not have a clean generic diffusers auto-load path here, and we
|
# WAN VAE does not have a clean generic diffusers auto-load path here, and we
|
||||||
# explicitly need checkpoint-loaded weights for reference-side transfer/parity.
|
# explicitly need checkpoint-loaded weights for reference-side transfer/parity.
|
||||||
@@ -168,9 +190,14 @@ def _load_reference_component(
|
|||||||
cls = getattr(diffusers, str(class_name), None) if class_name else None
|
cls = getattr(diffusers, str(class_name), None) if class_name else None
|
||||||
if cls is None:
|
if cls is None:
|
||||||
cls = diffusers.AutoencoderKL
|
cls = diffusers.AutoencoderKL
|
||||||
|
if cls is not diffusers.AutoencoderKL and os.path.exists(
|
||||||
|
os.path.join(comp_path, "model.safetensors")
|
||||||
|
):
|
||||||
|
return _load_reference_component_from_local_safetensors(
|
||||||
|
cls, comp_path, component.value
|
||||||
|
)
|
||||||
return cls.from_pretrained(
|
return cls.from_pretrained(
|
||||||
source_root,
|
comp_path,
|
||||||
subfolder=subfolder,
|
|
||||||
torch_dtype=torch.bfloat16,
|
torch_dtype=torch.bfloat16,
|
||||||
trust_remote_code=True,
|
trust_remote_code=True,
|
||||||
)
|
)
|
||||||
@@ -182,6 +209,14 @@ def _load_reference_component(
|
|||||||
"torch_dtype": torch.bfloat16,
|
"torch_dtype": torch.bfloat16,
|
||||||
"trust_remote_code": True,
|
"trust_remote_code": True,
|
||||||
}
|
}
|
||||||
|
if class_name:
|
||||||
|
maybe_cls = getattr(diffusers, str(class_name), None)
|
||||||
|
if maybe_cls is not None and os.path.exists(
|
||||||
|
os.path.join(comp_path, "model.safetensors")
|
||||||
|
):
|
||||||
|
return _load_reference_component_from_local_safetensors(
|
||||||
|
maybe_cls, comp_path, component.value
|
||||||
|
)
|
||||||
if cfg:
|
if cfg:
|
||||||
for k, out_k in [
|
for k, out_k in [
|
||||||
("in_dim", "in_channels"),
|
("in_dim", "in_channels"),
|
||||||
@@ -192,9 +227,7 @@ def _load_reference_component(
|
|||||||
if k in cfg:
|
if k in cfg:
|
||||||
load_kwargs[out_k] = cfg[k]
|
load_kwargs[out_k] = cfg[k]
|
||||||
candidates = [diffusers.AutoModel]
|
candidates = [diffusers.AutoModel]
|
||||||
if class_name:
|
if class_name and maybe_cls is not None:
|
||||||
maybe_cls = getattr(diffusers, str(class_name), None)
|
|
||||||
if maybe_cls is not None:
|
|
||||||
candidates.insert(0, maybe_cls)
|
candidates.insert(0, maybe_cls)
|
||||||
last_error: Optional[Exception] = None
|
last_error: Optional[Exception] = None
|
||||||
for cls in candidates:
|
for cls in candidates:
|
||||||
@@ -241,11 +274,30 @@ def _load_reference_component(
|
|||||||
|
|
||||||
# Public accuracy engine
|
# Public accuracy engine
|
||||||
class AccuracyEngine:
|
class AccuracyEngine:
|
||||||
|
@staticmethod
|
||||||
|
def prepare_component_for_release(module: nn.Module) -> None:
|
||||||
|
for submodule in module.modules():
|
||||||
|
reset_teacache_state = getattr(submodule, "reset_teacache_state", None)
|
||||||
|
if callable(reset_teacache_state):
|
||||||
|
reset_teacache_state()
|
||||||
|
|
||||||
|
seen_names: set[str] = set()
|
||||||
|
for cls in type(submodule).__mro__:
|
||||||
|
for name, attr in cls.__dict__.items():
|
||||||
|
if name in seen_names:
|
||||||
|
continue
|
||||||
|
seen_names.add(name)
|
||||||
|
|
||||||
|
cache_clear = getattr(attr, "cache_clear", None)
|
||||||
|
if callable(cache_clear):
|
||||||
|
cache_clear()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def reset_parallel_runtime() -> None:
|
def reset_parallel_runtime() -> None:
|
||||||
if torch.distributed.is_initialized():
|
if torch.distributed.is_initialized():
|
||||||
torch.distributed.barrier()
|
if torch.distributed.get_world_size() == 1:
|
||||||
if model_parallel_is_initialized():
|
cleanup_dist_env_and_memory()
|
||||||
|
elif model_parallel_is_initialized():
|
||||||
destroy_model_parallel()
|
destroy_model_parallel()
|
||||||
gc.collect()
|
gc.collect()
|
||||||
if torch.cuda.is_available():
|
if torch.cuda.is_available():
|
||||||
@@ -476,6 +528,8 @@ class AccuracyEngine:
|
|||||||
num_gpus,
|
num_gpus,
|
||||||
component_selection.component_paths,
|
component_selection.component_paths,
|
||||||
)
|
)
|
||||||
|
if component == ComponentType.TRANSFORMER and not materialize_sgl_on_device:
|
||||||
|
sgl_args.dit_cpu_offload = True
|
||||||
initialize_parallel_runtime(sgl_args)
|
initialize_parallel_runtime(sgl_args)
|
||||||
set_global_server_args(sgl_args)
|
set_global_server_args(sgl_args)
|
||||||
|
|
||||||
@@ -497,11 +551,9 @@ class AccuracyEngine:
|
|||||||
|
|
||||||
ref_component = _load_reference_component(
|
ref_component = _load_reference_component(
|
||||||
component_selection.source_path,
|
component_selection.source_path,
|
||||||
component_selection.source_root,
|
|
||||||
component,
|
component,
|
||||||
hub_id,
|
hub_id,
|
||||||
sgl_args.pipeline_config,
|
sgl_args.pipeline_config,
|
||||||
component_selection.source_subfolder,
|
|
||||||
)
|
)
|
||||||
if materialize_ref_on_device:
|
if materialize_ref_on_device:
|
||||||
ref_component = ref_component.to(device=device, dtype=torch.bfloat16)
|
ref_component = ref_component.to(device=device, dtype=torch.bfloat16)
|
||||||
|
|||||||
@@ -179,6 +179,9 @@ class ServerContext:
|
|||||||
# Clean up downloaded models if HF cache is not persistent
|
# Clean up downloaded models if HF cache is not persistent
|
||||||
# This prevents disk exhaustion in CI when cache is not mounted
|
# This prevents disk exhaustion in CI when cache is not mounted
|
||||||
self._cleanup_hf_cache_if_not_persistent()
|
self._cleanup_hf_cache_if_not_persistent()
|
||||||
|
else:
|
||||||
|
# Give the runtime a brief cooldown after server shutdown.
|
||||||
|
time.sleep(2)
|
||||||
|
|
||||||
def _cleanup_hf_cache_if_not_persistent(self) -> None:
|
def _cleanup_hf_cache_if_not_persistent(self) -> None:
|
||||||
"""Clean up HF cache if it's not on a persistent volume.
|
"""Clean up HF cache if it's not on a persistent volume.
|
||||||
|
|||||||
@@ -271,6 +271,8 @@ def handle_rerun_stage(
|
|||||||
"stage-c-test-deepep-8-gpu-h200",
|
"stage-c-test-deepep-8-gpu-h200",
|
||||||
"multimodal-gen-test-1-gpu",
|
"multimodal-gen-test-1-gpu",
|
||||||
"multimodal-gen-test-2-gpu",
|
"multimodal-gen-test-2-gpu",
|
||||||
|
"multimodal-gen-component-accuracy-1-gpu",
|
||||||
|
"multimodal-gen-component-accuracy-2-gpu",
|
||||||
"multimodal-gen-test-1-b200",
|
"multimodal-gen-test-1-b200",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user