Skip to content

[Feat] support CFG Parallel for FLUX kontext - #2281

Merged
wtomin merged 16 commits into
vllm-project:mainfrom
RuixiangMa:knotextcfg
Jul 20, 2026
Merged

wtomin merged 16 commits into
vllm-project:mainfrom
RuixiangMa:knotextcfg

Conversation

@RuixiangMa

@RuixiangMa RuixiangMa commented Mar 28, 2026 •

Copy link
Copy Markdown
Collaborator

Purpose

support CFG Parallel for FLUX kontext

Test Plan

Test Result

#!/bin/bash

# Offline image-to-image test matrix.
# Compare eager/non-eager and cfg-parallel on/off.

export CUDA_VISIBLE_DEVICES=1,2,3,4

PROMPT="Add a hat to the dog"
IMAGE="dog.png"
NEGATIVE_PROMPT="ugly, unclear, blurry, gray"
CFG_SCALE=4.0

# Arrays to track success and failure
declare -a SUCCESS_TASKS
declare -a FAILED_TASKS

# Format: "model_name|model_path"
declare -a MODELS=(
  "FLUX.1-Kontext-dev|black-forest-labs/FLUX.1-Kontext-dev"
)

# Eager mode configurations
declare -a EAGER_CONFIGS=(
  "no_eager|"
  "with_eager|--enforce-eager"
)

# CFG parallel configurations
declare -a CFG_CONFIGS=(
  "no_cfg_parallel|"
  "with_cfg_parallel|--cfg-parallel-size 2"
)

echo "=========================================="
echo "Starting offline image edit inference tests"
echo "Script: examples/offline_inference/image_to_image/image_edit.py"
echo "Testing combinations of eager mode and CFG parallel"
echo "=========================================="
echo ""

if [[ ! -f "$IMAGE" ]]; then
  echo "Input image not found: $IMAGE"
  exit 1
fi

TASK_NUM=0
TOTAL_TASKS=$((${#MODELS[@]} * ${#EAGER_CONFIGS[@]} * ${#CFG_CONFIGS[@]}))

for model_info in "${MODELS[@]}"; do
  IFS='|' read -r model_name model_path <<< "$model_info"

  model_dir="${model_name// /_}"
  mkdir -p "$model_dir"

  for eager_info in "${EAGER_CONFIGS[@]}"; do
    IFS='|' read -r eager_label eager_args <<< "$eager_info"

    for cfg_info in "${CFG_CONFIGS[@]}"; do
      IFS='|' read -r cfg_label cfg_args <<< "$cfg_info"
      TASK_NUM=$((TASK_NUM + 1))

      base_name="${model_name,,}"
      base_name="${base_name// /_}"
      output_file="$model_dir/${base_name}_output_${eager_label}_${cfg_label}.png"
      log_file="$model_dir/${base_name}_${eager_label}_${cfg_label}.log"
      task_label="$model_name ($eager_label + $cfg_label)"

      # no_cfg_parallel: TP=2 (2 GPUs)
      # with_cfg_parallel: TP=2 + CFG=2 (4 GPUs)
      tp_size=2

      echo "=========================================="
      echo "$TASK_NUM/$TOTAL_TASKS: Running $task_label..."
      echo "=========================================="
      echo "Using CFG scale: $CFG_SCALE"

      if python examples/offline_inference/image_to_image/image_edit.py \
        --model "$model_path" \
        --cfg-scale "$CFG_SCALE" \
        --prompt "$PROMPT" \
        --negative-prompt "$NEGATIVE_PROMPT" \
        --tensor-parallel-size "$tp_size" \
        --enable-cpu-offload \
        --image "$IMAGE" \
        --output "$output_file" \
        $eager_args \
        $cfg_args \
        2>&1 | tee "$log_file"; then
        echo "PASS $task_label completed."
        SUCCESS_TASKS+=("$task_label")
      else
        echo "FAIL $task_label failed."
        FAILED_TASKS+=("$task_label")
      fi
      echo ""
    done
  done
done

echo "=========================================="
echo "All tasks completed!"
echo "=========================================="
echo "Summary: ${#SUCCESS_TASKS[@]}/$TOTAL_TASKS successful, ${#FAILED_TASKS[@]}/$TOTAL_TASKS failed"
echo ""

if [ ${#SUCCESS_TASKS[@]} -gt 0 ]; then
  echo "PASS Successful tasks:"
  for task in "${SUCCESS_TASKS[@]}"; do
    echo "  - $task"
  done
  echo ""
fi

if [ ${#FAILED_TASKS[@]} -gt 0 ]; then
  echo "FAIL Failed tasks:"
  for task in "${FAILED_TASKS[@]}"; do
    echo "  - $task"
  done
  echo ""
  echo "Check model directories for error logs."
  echo ""
fi

echo "Output directories:"
for model_info in "${MODELS[@]}"; do
  IFS='|' read -r model_name _ <<< "$model_info"
  model_dir="${model_name// /_}"
  echo "  - $model_dir/"
done

if [ ${#FAILED_TASKS[@]} -gt 0 ]; then
  exit 1
fi
Configuration Total Time
no_eager_no_cfg_parallel 114.822s
no_eager_with_cfg_parallel 67.569s
with_eager_no_cfg_parallel 117.827s
with_eager_with_cfg_parallel 68.837s

Essential Elements of an Effective PR Description Checklist
  • The purpose of the PR, such as "Fix some issue (link existing issues this PR will resolve)".
  • The test plan. Please provide the test scripts & test commands. Please state the reasons if your codes don't require additional test scripts. For test file guidelines, please check the test style doc
  • The test results. Please paste the results comparison before and after, or the e2e results.
  • (Optional) The necessary documentation update, such as updating supported_models.md and examples for a new model. Please run mkdocs serve to sync the documentation editions to ./docs.
  • (Optional) Release notes update. If your change is user-facing, please update the release notes draft.

BEFORE SUBMITTING, PLEASE READ https://github.com/vllm-project/vllm-omni/blob/main/CONTRIBUTING.md (anything written below this line will be removed by GitHub Actions)

Signed-off-by: Lancer <maruixiang6688@gmail.com>

@lishunyang12 lishunyang12 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

left a couple comments

img_ids=latent_ids,
joint_attention_kwargs=self.joint_attention_kwargs,
return_dict=False,
)[0]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

check_cfg_parallel_validity returns False on invalid config but the return value is discarded here. Should this raise or at least skip the CFG path? Right now an invalid config silently runs and produces bad output.

@RuixiangMa RuixiangMa Apr 5, 2026 •

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Now, the CFG path now respects check_cfg_parallel_validity(...) instead of discarding the return value, so invalid CFG-parallel configurations fall back cleanly instead of continuing with bad output.

raise NotImplementedError("Subclasses must implement diffuse")

def check_cfg_parallel_validity(self, true_cfg_scale: float, has_neg_prompt: bool) -> bool:
"""

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Nit: the mixin already imports from vllm_omni.diffusion.distributed.parallel_state — is there a project-wide logger convention (e.g. from vllm) you could use instead of import logging + getLogger? Minor.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Thx, fixed

Signed-off-by: Lancer <maruixiang6688@gmail.com>
Signed-off-by: Lancer <maruixiang6688@gmail.com>
Signed-off-by: Lancer <maruixiang6688@gmail.com>
Signed-off-by: Lancer <maruixiang6688@gmail.com>
@RuixiangMa

Copy link
Copy Markdown
Collaborator Author

@hsliuustc0106 verified it and ready to merge

)
do_true_cfg = true_cfg_scale > 1.0 and has_neg_prompt

do_true_cfg = do_true_cfg and self.check_cfg_parallel_validity(true_cfg_scale, has_neg_prompt)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

About the CFG scale, I notice in FLUX.1-Kontext-dev HF webpage, diffusers use guidance_scale not true_cfg_scale. Please double check. Better to stay consistent with diffusers' key name.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

FLUX.1-dev HF webpage uses guidance_scale too. I am indeed very confused about the two key names: guidance_scale and true_cfg_scale.

@wtomin

wtomin commented May 14, 2026

Copy link
Copy Markdown
Collaborator

Please update docs/user_guide/diffusion_features.md. Besides, please increase the CFG parallel feature in tests/e2e/online_serving/test_flux_kontext_expansion.py, taking tests/e2e/online_serving/test_flux_2_dev_expansion.py as an example.

Signed-off-by: Lancer <maruixiang6688@gmail.com>
Signed-off-by: Lancer <maruixiang6688@gmail.com>
@RuixiangMa

Copy link
Copy Markdown
Collaborator Author

Please update docs/user_guide/diffusion_features.md. Besides, please increase the CFG parallel feature in tests/e2e/online_serving/test_flux_kontext_expansion.py, taking tests/e2e/online_serving/test_flux_2_dev_expansion.py as an example.

updated it

@wtomin

wtomin commented Jun 22, 2026

Copy link
Copy Markdown
Collaborator

@RuixiangMa Pls resolve the conflicts. When it is ready, I think we can launch a nightly CI test for this PR.

Signed-off-by: Lancer <maruixiang6688@gmail.com>
@RuixiangMa RuixiangMa added the nightly-test label to trigger buildkite nightly test CI label Jun 22, 2026
@wtomin wtomin removed the nightly-test label to trigger buildkite nightly test CI label Jun 24, 2026
@wtomin wtomin added this to the v0.24.0 milestone Jun 24, 2026
@wtomin

wtomin commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

@hsliuustc0106 Could you please add the label related diffusion text to image CI test? The npu ci test failure is not relevant to this PR, I think.

I think the nightly CI label is too large, so I removed it. @RuixiangMa

@RuixiangMa

RuixiangMa commented Jun 24, 2026 •

Copy link
Copy Markdown
Collaborator Author

is too large, so I remo

Thx, get it

@wtomin

wtomin commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

I notice that the nightly CI failed:

[2026-06-25T03:11:09Z] =========================== short test summary info ============================
--
  | [2026-06-25T03:11:09Z] ERROR tests/e2e/online_serving/test_flux2_expansion.py::test_flux2_klein[layerwise_hsdp] - RuntimeError: Server processes exited with code 1 before becoming ready.
  | [2026-06-25T03:11:09Z] ERROR tests/e2e/online_serving/test_flux_kontext_expansion.py::test_flux_kontext_text_to_image[parallel_tp_2] - RuntimeError: Server processes exited with code 1 before becoming ready.
  | [2026-06-25T03:11:09Z] ERROR tests/e2e/online_serving/test_flux_kontext_expansion.py::test_flux_kontext_image_edit[parallel_tp_2] - RuntimeError: Server processes exited with code 1 before becoming ready.
  | [2026-06-25T03:11:09Z] ERROR tests/e2e/online_serving/test_flux_kontext_expansion.py::test_flux_kontext_image_edit_no_negative[parallel_tp_2] - RuntimeError: Server processes exited with code 1 before becoming ready.
  | [2026-06-25T03:11:09Z] ERROR tests/e2e/online_serving/test_flux_kontext_expansion.py::test_flux_kontext_high_resolution[parallel_tp_2] - RuntimeError: Server processes exited with code 1 before becoming ready.
  | [2026-06-25T03:11:09Z] ERROR tests/e2e/online_serving/test_flux_kontext_expansion.py::test_flux_kontext_multiple_outputs[parallel_tp_2] - RuntimeError: Server processes exited with code 1 before becoming ready.
  | [2026-06-25T03:11:09Z] ERROR tests/e2e/online_serving/test_flux_kontext_expansion.py::test_flux_kontext_text_to_image[parallel_cfg_2] - RuntimeError: Server processes exited with code 1 before becoming ready.
  | [2026-06-25T03:11:09Z] ERROR tests/e2e/online_serving/test_flux_kontext_expansion.py::test_flux_kontext_image_edit[parallel_cfg_2] - RuntimeError: Server processes exited with code 1 before becoming ready.
  | [2026-06-25T03:11:09Z] ERROR tests/e2e/online_serving/test_flux_kontext_expansion.py::test_flux_kontext_image_edit_no_negative[parallel_cfg_2] - RuntimeError: Server processes exited with code 1 before becoming ready.
  | [2026-06-25T03:11:09Z] ERROR tests/e2e/online_serving/test_flux_kontext_expansion.py::test_flux_kontext_high_resolution[parallel_cfg_2] - RuntimeError: Server processes exited with code 1 before becoming ready.
  | [2026-06-25T03:11:09Z] ERROR tests/e2e/online_serving/test_flux_kontext_expansion.py::test_flux_kontext_multiple_outputs[parallel_cfg_2] - RuntimeError: Server processes exited with code 1 before becoming ready.
  | [2026-06-25T03:11:09Z] = 17 passed, 4 skipped, 398 deselected, 22 warnings, 11 errors in 3168.67s (0:52:48) =

Could you pls run this test tests/e2e/online_serving/test_flux_kontext_expansion.py locally to check if it is correct?

And please resolve the conflicts.

@RuixiangMa
RuixiangMa requested a review from xuechendi as a code owner July 10, 2026 01:38
Signed-off-by: Lancer <maruixiang6688@gmail.com>
@RuixiangMa

Copy link
Copy Markdown
Collaborator Author

I notice that the nightly CI failed:

[2026-06-25T03:11:09Z] =========================== short test summary info ============================
--
  | [2026-06-25T03:11:09Z] ERROR tests/e2e/online_serving/test_flux2_expansion.py::test_flux2_klein[layerwise_hsdp] - RuntimeError: Server processes exited with code 1 before becoming ready.
  | [2026-06-25T03:11:09Z] ERROR tests/e2e/online_serving/test_flux_kontext_expansion.py::test_flux_kontext_text_to_image[parallel_tp_2] - RuntimeError: Server processes exited with code 1 before becoming ready.
  | [2026-06-25T03:11:09Z] ERROR tests/e2e/online_serving/test_flux_kontext_expansion.py::test_flux_kontext_image_edit[parallel_tp_2] - RuntimeError: Server processes exited with code 1 before becoming ready.
  | [2026-06-25T03:11:09Z] ERROR tests/e2e/online_serving/test_flux_kontext_expansion.py::test_flux_kontext_image_edit_no_negative[parallel_tp_2] - RuntimeError: Server processes exited with code 1 before becoming ready.
  | [2026-06-25T03:11:09Z] ERROR tests/e2e/online_serving/test_flux_kontext_expansion.py::test_flux_kontext_high_resolution[parallel_tp_2] - RuntimeError: Server processes exited with code 1 before becoming ready.
  | [2026-06-25T03:11:09Z] ERROR tests/e2e/online_serving/test_flux_kontext_expansion.py::test_flux_kontext_multiple_outputs[parallel_tp_2] - RuntimeError: Server processes exited with code 1 before becoming ready.
  | [2026-06-25T03:11:09Z] ERROR tests/e2e/online_serving/test_flux_kontext_expansion.py::test_flux_kontext_text_to_image[parallel_cfg_2] - RuntimeError: Server processes exited with code 1 before becoming ready.
  | [2026-06-25T03:11:09Z] ERROR tests/e2e/online_serving/test_flux_kontext_expansion.py::test_flux_kontext_image_edit[parallel_cfg_2] - RuntimeError: Server processes exited with code 1 before becoming ready.
  | [2026-06-25T03:11:09Z] ERROR tests/e2e/online_serving/test_flux_kontext_expansion.py::test_flux_kontext_image_edit_no_negative[parallel_cfg_2] - RuntimeError: Server processes exited with code 1 before becoming ready.
  | [2026-06-25T03:11:09Z] ERROR tests/e2e/online_serving/test_flux_kontext_expansion.py::test_flux_kontext_high_resolution[parallel_cfg_2] - RuntimeError: Server processes exited with code 1 before becoming ready.
  | [2026-06-25T03:11:09Z] ERROR tests/e2e/online_serving/test_flux_kontext_expansion.py::test_flux_kontext_multiple_outputs[parallel_cfg_2] - RuntimeError: Server processes exited with code 1 before becoming ready.
  | [2026-06-25T03:11:09Z] = 17 passed, 4 skipped, 398 deselected, 22 warnings, 11 errors in 3168.67s (0:52:48) =

Could you pls run this test tests/e2e/online_serving/test_flux_kontext_expansion.py locally to check if it is correct?

And please resolve the conflicts.

image

Yes, local testing works fine;

I suspect that FLUX.1-Kontext-dev et al are all gated models on HuggingFace. If the CI environment doesn't have an HF_TOKEN with approved access to these repos, the model download would fail and the tests would error. I added skip_if_gated_repo_inaccessible()

@hsliuustc0106 hsliuustc0106 added diffusion codes related to diffusion models enhancement New feature or request labels Jul 17, 2026 — with ChatGPT Codex Connector

@wtomin wtomin left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM.

@wtomin
wtomin merged commit eef3bd5 into vllm-project:main Jul 20, 2026
6 checks passed
y-null pushed a commit to y-null/vllm-omni that referenced this pull request Jul 21, 2026
Signed-off-by: Lancer <maruixiang6688@gmail.com>
Signed-off-by: y_null <y_null@qq.com>
bowieshi pushed a commit to bowieshi/vllm-omni that referenced this pull request Jul 22, 2026
Signed-off-by: Lancer <maruixiang6688@gmail.com>
nagisa-kunhah pushed a commit to nagisa-kunhah/vllm-omni that referenced this pull request Jul 30, 2026
Signed-off-by: Lancer <maruixiang6688@gmail.com>
khairulkabir1661 pushed a commit to khairulkabir1661/vllm-omni that referenced this pull request Sep 25, 2026
Signed-off-by: Lancer <maruixiang6688@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

diffusion codes related to diffusion models enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants