Repository navigation
[prompt_enhance,model,cli,docs] feat: move prompt enhancement into ff-prompt-enhance - #248
Merged
Merged
Conversation
…-prompt-enhance Training now encodes every dataset prompt verbatim. Prompt enhancement is a separate offline step that writes a new dataset, so whether and how prompts are enhanced is decided before training. - Remove FLUX.2 caption upsampling and LTX2 prompt enhancement from the adapters, together with their example config keys. - Add flow_factory.prompt_enhance: a registry of enhancers (flux2, ltx2, flux3 prompt upsampler, openai-compatible servers) and a sharded runner that writes num_variants rows per source row with source_prompt and pe_variant, per-row seeds, fingerprinted resumable parts, symlinked media, and a manifest. - Add the ff-prompt-enhance launcher, sharing the ff-train launch logic. - Document the workflow in guidance/prompt_enhance.md and route the new package in the agent harness.
Contributor
There was a problem hiding this comment.
Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.
An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.
Flux2Pipeline.upsample_prompt pads every prompt to 2048 tokens before calling generate. The FLUX.2-dev Mistral tokenizer pads on the right, so the first new token was predicted from a pad position: with transformers 5.14 the outputs ignored the prompt and echoed the system message's numbered rules. Left padding restores faithful captions on real weights.
… processor diffusers/LTX-2.3-Diffusers ships its Gemma3 processor under processor/ without declaring it in model_index.json, so from_pretrained leaves the component unset and the ltx2 enhancer failed. Load processor/processor_config.json when the checkpoint ships it, and still fail fast when it has neither (as Lightricks/LTX-2 does). Point the example at diffusers/LTX-2.3-Diffusers and state the requirement in the guide.
This was referenced Oct 17, 2026
…UX.3 GenEval GRPO example dataset/geneval_flux3_pe is the flux3 enhancer's rewrite of the GenEval test split and the first 1024 train rows, produced by examples/prompt_enhance/flux3_geneval.yaml. Its README records the upsampler revision and the one test row regenerated with sampling after greedy decoding degenerated. examples/grpo/lora/flux3/geneval.yaml is examples/grpo/lora/sd3_5/geneval.yaml with only the model (FLUX.3 klein base) and the dataset swapped. It needs the flux3 model adapter.
…rompt enhancers qwen-image-2.1-t2i and qwen-image-2.1-i2i run Qwen/Qwen-Image-2.1-PE-T2I and -PE-I2I with the official prompt_rewrite recipe: the checkpoint's system_prompt.txt, images before the text and downscaled to at most 1024x1024 pixels, thinking enabled, and each task's official sampling profile with a vLLM-style presence penalty. The enhanced prompt is the answer's rewritten_prompt; the wh_ratio / ratio_follow canvas recommendation is not recorded because training renders at the configured resolution. Generation stops at <|im_end|> as well as the <|endoftext|> in the checkpoints' generation_config. A row whose sampled rewrite loops until max_new_tokens or answers without a parseable rewritten_prompt is resampled from the continuing RNG stream of its seed, up to three attempts; the T2I enhancer rejects rows with reference images and the I2I enhancer rows without one.
…and a Qwen-Image-2.1 GenEval GRPO example dataset/geneval_qwen_image_21_pe is the qwen-image-2.1-t2i enhancer's rewrite of the GenEval test split and the first 1024 train rows, produced by examples/prompt_enhance/qwen_image_2_1_geneval.yaml with the official T2I sampling profile. Its README records the rewriter revision. examples/grpo/lora/qwen_image_2_1/geneval.yaml is examples/grpo/lora/sd3_5/geneval.yaml with the model and the dataset swapped, plus per_device_batch_size 1 for rollout and evaluation, which the Qwen-Image-2.1 adapter requires.
Resolve the README news conflict with the FLUX.3 adapter (#247) by keeping both entries, newest first.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Training now feeds every dataset
promptto the model verbatim. Prompt enhancement moves out of theadapters into a separate offline step,
ff-prompt-enhance, which rewrites a dataset's prompts with anenhancer model and writes a new dataset. Whether to enhance, with which model, and how many rewrites
per prompt are decided before training, so training needs no prompt-enhancement logic or checks.
The PR also ships GenEval prompts rewritten by the FLUX.3 and Qwen-Image-2.1 enhancers, with GRPO
examples that train on them.
Changes
Adapters: remove FLUX.2 caption upsampling (
caption_upsample_temperature) and LTX2 promptenhancement (
system_prompt,prompt_enhancement_seed, and theimageargument of the LTX2 I2AVencode_prompt), plus their keys in the LTX2 GRPO examples.flow_factory.prompt_enhance:BasePromptEnhancer, a registry, and six enhancers:enhancerflux3black-forest-labs/flux-3-image-klein-pup(itst2i/i2isystem prompts, reference images in order)flux2Flux2Pipeline.upsample_prompt; only the text components are loadedltx2prompt_enhancer, throughLTX2Pipeline.enhance_prompt; needs a Gemma3 processor, e.g.diffusers/LTX-2.3-Diffusersqwen-image-2.1-t2iQwen/Qwen-Image-2.1-PE-T2I, prompt-only rowsqwen-image-2.1-i2iQwen/Qwen-Image-2.1-PE-I2I, image-editing rows (one or more references)openai-compatibleThe two Qwen-Image-2.1 enhancers follow the official
prompt_rewriterecipe:system_prompt.txt;presence_penalty: 1.5andmax_new_tokens: 16256, edit nopresence penalty and
max_new_tokens: 24000. transformers has no presence penalty, so theenhancers apply a vLLM-style logits processor.
The enhanced prompt is the answer's
rewritten_prompt. Thewh_ratio/ratio_followcanvasrecommendation is dropped because training renders at the configured resolution. Two deviations
from the official transformers script:
<|im_end|>, because the checkpoints'generation_configlists only<|endoftext|>;max_new_tokens, or answers without a parseablerewritten_prompt, is resampled from the continuing RNG stream of its seed, up to threeattempts. The official script keeps the raw text with
parse_ok: falseinstead.Runner: each rank enhances a disjoint row shard. The output split has
num_variantsrows persource row, with variants adjacent;
promptis the enhanced text,source_promptandpe_variantare added, and all other fields are kept. Media directories are symlinked, and
prompt_enhance_manifest.jsonrecords the run.(row, variant)gets the seedseed + variant * num_rows + row, independent ofbatch_sizeand the process count.and source rows; resuming under a different fingerprint fails, while raising
num_variantsextends a finished run.
CLI:
ff-prompt-enhance/flow-factory-prompt-enhance, sharing theff-trainlauncher.GenEval datasets and examples: both datasets cover the GenEval test split (553 rows) and the
first 1024 train rows, which is the slice
max_dataset_size: 1024trains on. They keep theinclude/exclude/tagfields the reward scores, and each has a README with the enhancerrevision.
dataset/geneval_flux3_peexamples/prompt_enhance/flux3_geneval.yaml(upstream greedy decoding; one degenerate row resampled, see its README)examples/grpo/lora/flux3/geneval.yaml(the FLUX.3 adapter from [model,test,docs] feat: add FLUX.3 adapter #247, now onmain)dataset/geneval_qwen_image_21_peexamples/prompt_enhance/qwen_image_2_1_geneval.yaml(official T2I sampling profile)examples/grpo/lora/qwen_image_2_1/geneval.yamlBoth training examples are
examples/grpo/lora/sd3_5/geneval.yamlwith only the model and thedataset swapped. The Qwen-Image-2.1 example also sets
per_device_batch_size: 1, which itsadapter requires.
Docs and harness:
guidance/prompt_enhance.md,examples/prompt_enhance/*.yaml, README,AGENTS.md, and architecture updates; a risk route and eval case forsrc/flow_factory/prompt_enhance/.Fixes from GPU validation
[prompt_enhance,test] fix: left-pad FLUX.2 upsampling promptsFlux2Pipeline.upsample_promptpads every prompt to 2048 tokens beforegenerate, and the FLUX.2-dev Mistral tokenizer pads on the right, so the first new token was predicted from a pad position. With transformers 5.14 the outputs ignored the prompt and echoed the system message's numbered rules. The enhancer now sets left padding.[prompt_enhance,test,docs] fix: load the undeclared LTX-2.3 Diffusers processordiffusers/LTX-2.3-Diffusersships its Gemma3 processor underprocessor/without declaring it inmodel_index.json, so the enhancer failed. It now loadsprocessor/processor_config.jsonwhen the checkpoint ships it and still fails fast when it has neither (asLightricks/LTX-2does). The example points atdiffusers/LTX-2.3-Diffusers.Compatibility
Configs that still set
caption_upsample_temperature,system_prompt, orprompt_enhancement_seedkeep loading. The keys land in
extra_kwargswith the existing unknown-key warning and no longer havean effect. To train on enhanced prompts, run
ff-prompt-enhanceand pointdataset_dirat its output.The removed FLUX.2 path appended the list returned by
upsample_promptinto the prompt list, and itinherited the right-padding problem above, so it did not produce usable prompts before this change
either.
Re-run
pip install -e .to register the new console scripts.Validation
CPU
tests/prompt_enhance, 33 tests:GeneralDatasetconsuming the output unchanged;diffusers/transformerssignatures pinned,including FLUX.2 left padding and loading an undeclared LTX2
processor/subfolder;semantics; image downscaling; answer parsing; resampling within a row's seed; and rejecting rows
of the other task;
main(which now carries [model,test,docs] feat: add FLUX.3 adapter #247 and the Diffusers pin7ecb1e1b): 3042 passed, 50 skipped.prompt_enhance_cli;data-URL images).
scripts/agent_scope.py: R2. Harness validator and docstring audit are clean.GPU (8x H20, Python 3.12, torch 2.10.0+cu129, transformers 5.14.1)
Flux2Pipeline.upsample_promptandLTX2Pipeline.enhance_promptare identical at the repository'sDiffusers pin and at the FLUX.3 pin
7ecb1e1b; the runs used the latter. Every run went throughprompt_enhance_cli.flux3,flux-3-image-klein-pup, 8 ranks,num_variants: 2, sampling, 16 image-editing + 16 prompt-only rows<think>or chat-template remnants and no truncated captions; image rows describe their references; the Chinese prompt yields a faithful English caption. 233-429 tokens.output_dirwithseed: 43raisedValueError: ... was written with different ['seed'].flux2, localFLUX.2-devtext encoder, 2 ranksltx2,diffusers/LTX-2.3-Diffusersdedicated_prompt_enhancer: false. 70-158 tokens. Before the fix the same checkpoint failed fast at load.qwen-image-2.1-t2i/-i2iagainst the officialrun_transformers.pyreference, on the official example inputs with Flow-Factory's per-row seeds<image1>/<image2>composite. On the 7th, "Translate into Hindi." with a 3840×2160 source and seed 43, both implementations generate the same loop until the 24000-token limit. The reference keeps the raw thinking text withparse_ok: false; the enhancer logged the failed attempt, resampled, and wrote a grounded rewrite that replaces the image's Japanese title.qwen-image-2.1-t2i, 8 ranks, 8pickscoreprompts × 2 variants"philo is a weird"survives verbatim; the manifest records the effective profile and the checkpoint system-prompt hash.qwen-image-2.1-i2i, 8 ranks, 8sharegpt4o_image_miniediting rows × 2 variantsimagesis symlinked and theimagefield kept.dataset/geneval_qwen_image_21_pe, 48 ranks on 6 nodeshair dryer,sofa,doughnut), which the detector-based reward does not depend on.examples/grpo/lora/flux3/geneval.yamlwith #247, #248, and #249 merged; 8 GPUs, ZeRO-2, 10 epochslora_Breached 0.0021 after 20 steps.examples/grpo/lora/qwen_image_2_1/geneval.yaml; 4 GPUs, 1 epoch, a reduced per-epoch sample countEvery observed length fits the matching training adapter's default
max_sequence_length(FLUX.38192, FLUX.2 512, LTX2 1024); the Qwen-Image-2.1 adapter does not truncate prompts. FLUX.2's longest
caption is close to its limit, as the guide warns. The Qwen-Image-2.1 rewriters generate about 34
tokens/s per H20 here, because the environment lacks the flash-linear-attention kernels and
transformers falls back to torch.
Not run:
openai-compatibleagainst a real vLLM server (covered by the local HTTP server above), and theofficial
run_vllm.pypath for the Qwen-Image-2.1 rewriters.prompt_enhancerpath: no Diffusers-format LTX-2.5 checkpoint is published.and the LTX2 examples set them to
null.