-
Notifications
You must be signed in to change notification settings - Fork 61
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
support metadata files as CLI arg supplier #81
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for early discussion - several iterations expected to come from review
@@ -152,6 +152,76 @@ mflux-generate --model dev --prompt "Luxury food photograph" --steps 25 --seed 2 | |||
|
|||
- **`--controlnet-save-canny`** (optional, bool, default: False): If set, saves the Canny edge detection reference image used by ControlNet. | |||
|
|||
- **`--config-from-metadata`** or **`-C`** (optional, `str`): [EXPERIMENTAL] Path to a prior file saved via `--metadata`, or a compatible handcrafted config file adhering to the expected args schema. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Discussion in #80 reminded me that we also export exif data to image files, so that opens the possibility that you can pass in an image path here to, and if you pass in an image path that can act as --init-image
or --controlnet-image-path
implicitly!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice idea, I think that would work!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
instead of adding Issues noise, I'll mark some todos for upcoming PRs inline here
- add
--config-from-image
option where theImage
is--init-image
while the exif metadata is the run config
"type": ["integer", "null"] | ||
}, | ||
"steps": { | ||
"type": ["integer", "null"] | ||
}, | ||
"guidance": { | ||
"type": ["number", "null"] | ||
}, | ||
"quantize": { | ||
"type": ["null", "string"] | ||
}, | ||
"lora_paths": { | ||
"type": ["array", "null"], | ||
"items": { | ||
"type": "string" | ||
} | ||
}, | ||
"lora_scales": { | ||
"type": ["array", "null"], | ||
"items": { | ||
"type": "number" | ||
} | ||
}, | ||
"prompt": { | ||
"type": ["string", "null"] | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for now just the basic image gen + lora args, withholding the controlnet implementation for now, because there are plans to dedupe/consolidate the two classes together so that would cause change in this PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great to also added the schema here! Make sense - lets start start with this and update the schema after that refactoring
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
todo:
- add support for
--config-from-metadata
in controlnet workflow
src/mflux/config/runtime_config.py
Outdated
@property | ||
def init_image_path(self) -> int: | ||
return self.config.init_image_path | ||
|
||
@property | ||
def init_image_strength(self) -> int: | ||
return self.config.init_image_strength | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we have some anti-patterns in the relation between "runtime config" and "model config", there's a lot of proxying things through nested config objects. I have some refactoring ideas here but for now I want to keep the config structure as-is so I don't bloat the change and add unrelated changes to the actual intent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good! I agree with you that it is not the optimal way of structuring things... More generally, it is also a bit unclear what exactly should go in to the config. For example, now the seed is not included there, but one could argue that it is a type of config etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
todo:
- refactor config classes to have clarity on separation of responsibility and scope
"lora_scales": ", ".join([f"{scale:.2f}" for scale in self.lora_scales]) if self.lora_scales else "None", | ||
"seed": self.seed, | ||
"steps": self.steps, | ||
"guidance": self.guidance if ModelConfig.FLUX1_DEV else None, # only the dev model supports guidance |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I noticed the prior implementation and accepted the logic as is, but want to double check this is true: only the dev model supports guidance
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, only the dev
model supports guidance. Right now, we pass the guidance value down to the lower level classes (regardless of model choice), but at some point deeper down, we do a check like the following:
self.guidance_embedder = GuidanceEmbedder() if model_config == ModelConfig.FLUX1_DEV else None
and the guidance value is subsequently only used in case of "dev"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
blocker/todo for #84
- guidance should be turned on for dev-like models as well (e.g. Freepik in support HF models - freepik as first example #84)
6d5d213
to
c9dc66e
Compare
self.add_argument("--controlnet-strength", type=float, default=ui_defaults.CONTROLNET_STRENGTH, help=f"Controls how strongly the control image influences the output image. A value of 0.0 means no influence. (Default is {ui_defaults.CONTROLNET_STRENGTH})") | ||
self.add_argument("--controlnet-save-canny", action="store_true", help="If set, save the Canny edge detection reference input image.") | ||
|
||
def add_metadata_config(self) -> None: | ||
self.supports_metadata_config = True | ||
self.add_argument("--config-from-metadata", "-C", type=Path, required=False, default=argparse.SUPPRESS, help="Re-use the parameters from prior metadata. Params from metadata are secondary to other args you provide.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
perhaps better to call this simply --config
where the metadata-derived files are simply one way of supplying the config
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@filipstrand what do you think about simplifying the flag to --config
and keep -C
or maybe generically --config-from-file
/ -F
I think both have many precedents in CLI tools.
c9dc66e
to
03c5846
Compare
src/mflux/ui/cli/parsers.py
Outdated
if path_type == "load": | ||
group = self.add_mutually_exclusive_group(required=True) | ||
group.add_argument("--model", "-m", type=str, choices=ui_defaults.MODEL_CHOICES, help=f"The model to use ({' or '.join(ui_defaults.MODEL_CHOICES)}).") | ||
group.add_argument("--path", type=str, default=None, help="Local path for loading a model from disk") | ||
else: | ||
self.add_argument("--model", "-m", type=str, required=True, choices=ui_defaults.MODEL_CHOICES, help=f"The model to use ({' or '.join(ui_defaults.MODEL_CHOICES)}).") | ||
self.add_argument("--path", type=str, required=True, help="Local path for saving a model.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@filipstrand this diff does 3 things:
- important - fixes a real bug introduced in argparser refactor #75 - so you'll need to accept this PR or cherry-pick these changes before release. I'll try to cherry-pick into a smaller fix-it PR, as time allows in the next few days
- re-differentiate the two diff meanings of
--path
, one is for loading, one is the target ofmflux-save
. In save context it's required, in the load context it's not required. It may be a better idea to rename the save version to--output-path
though!
5bd1259
to
7a31241
Compare
@filipstrand in this PR I made major changes to the argparser expectations via adding the new config from file feature, so I added a test suite for all the various entry points. If you find any problems in
|
7a31241
to
dc61809
Compare
dc61809
to
351cc8b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
test results at this checkpoint:
================================================================================== test session starts ==================================================================================
platform darwin -- Python 3.11.9, pytest-8.3.3, pluggy-1.5.0 -- /Users/anthonywu/Desktop/workspace/mflux-ops/.venv/bin/python3
cachedir: .pytest_cache
rootdir: /Users/anthonywu/workspace/mflux-ops
configfile: pyproject.toml
testpaths: tests
plugins: anyio-4.6.0, timer-1.0.0
collected 17 items
run-last-failure: rerun previous 2 failures first
tests/test_generate_image_controlnet.py::TestImageGeneratorControlnet::test_image_generation_dev_controlnet PASSED [ 5%]
tests/test_generate_image_controlnet.py::TestImageGeneratorControlnet::test_image_generation_dev_lora_controlnet PASSED [ 11%]
tests/test_cli_argparser.py::test_model_path_requires_model_arg PASSED [ 17%]
tests/test_cli_argparser.py::test_prompt_arg PASSED [ 23%]
tests/test_cli_argparser.py::test_guidance_arg PASSED [ 29%]
tests/test_cli_argparser.py::test_quantize_arg PASSED [ 35%]
tests/test_cli_argparser.py::test_seed_arg PASSED [ 41%]
tests/test_cli_argparser.py::test_steps_arg PASSED [ 47%]
tests/test_cli_argparser.py::test_lora_args PASSED [ 52%]
tests/test_cli_argparser.py::test_image_to_image_args PASSED [ 58%]
tests/test_cli_argparser.py::test_controlnet_args PASSED [ 64%]
tests/test_cli_argparser.py::test_save_args PASSED [ 70%]
tests/test_generate_image.py::TestImageGenerator::test_image_generation_schnell PASSED [ 76%]
tests/test_generate_image.py::TestImageGenerator::test_image_generation_dev PASSED [ 82%]
tests/test_generate_image.py::TestImageGenerator::test_image_generation_dev_lora PASSED [ 88%]
tests/test_generate_image.py::TestImageGenerator::test_image_generation_dev_image_to_image PASSED [ 94%]
tests/test_generate_image_controlnet.py::TestImageGeneratorControlnet::test_image_generation_schnell_controlnet PASSED [100%]
===================================================================================== pytest-timer ======================================================================================
[success] 22.17% tests/test_generate_image_controlnet.py::TestImageGeneratorControlnet::test_image_generation_dev_lora_controlnet: 152.2725s
[success] 22.05% tests/test_generate_image_controlnet.py::TestImageGeneratorControlnet::test_image_generation_dev_controlnet: 151.4941s
[success] 16.29% tests/test_generate_image.py::TestImageGenerator::test_image_generation_dev: 111.8881s
[success] 16.09% tests/test_generate_image.py::TestImageGenerator::test_image_generation_dev_lora: 110.5325s
[success] 15.10% tests/test_generate_image.py::TestImageGenerator::test_image_generation_dev_image_to_image: 103.7386s
[success] 5.61% tests/test_generate_image_controlnet.py::TestImageGeneratorControlnet::test_image_generation_schnell_controlnet: 38.5621s
[success] 2.69% tests/test_generate_image.py::TestImageGenerator::test_image_generation_schnell: 18.5004s
[success] 0.00% tests/test_cli_argparser.py::test_model_path_requires_model_arg: 0.0006s
[success] 0.00% tests/test_cli_argparser.py::test_guidance_arg: 0.0004s
[success] 0.00% tests/test_cli_argparser.py::test_lora_args: 0.0004s
[success] 0.00% tests/test_cli_argparser.py::test_prompt_arg: 0.0004s
[success] 0.00% tests/test_cli_argparser.py::test_image_to_image_args: 0.0004s
[success] 0.00% tests/test_cli_argparser.py::test_quantize_arg: 0.0003s
[success] 0.00% tests/test_cli_argparser.py::test_seed_arg: 0.0003s
[success] 0.00% tests/test_cli_argparser.py::test_steps_arg: 0.0003s
[success] 0.00% tests/test_cli_argparser.py::test_controlnet_args: 0.0003s
[success] 0.00% tests/test_cli_argparser.py::test_save_args: 0.0002s
============================================================================ 17 passed in 688.04s (0:11:28) =============================================================================
@anthonywu I think this PR is looking really good and this is a nice feature that takes advantage of the metadata files - I initially just added them in case it was tricky for people to read the metadata embedded in the generated images themselves, and I was thinking that maybe it was a bit of a redundant feature to have, but now it feels like they have a proper purpose! Just had some smaller comments on this PR, if you mind having a look again. After that, I think we can merge this and do a Btw, I sent you an invite as a formal collaborator. Really appreciate your continuous involvement with this project!! |
Oct 19 - this is a preview of a big change that I think we'll discuss for several days. It probably should be in the (n+1)th release. I expect we'll go back and forth a few times here because the decisions here influence how other subsequent features are done.
Change
.json
files. This allows for very long commands with many path args to be easily re-usable for subsequent runs. You can imagine this being useful for anyone experimenting with changing one thing and seeing how that single variable affects the outcome.UX Demo
What the change allows are commands like:
mflux-generate --model dev --metadata --config-from-metadata <file>
- re-generate from yours or other's prior run configs. You can use these as references for checking into team repos, or to use as the control config in a test suite where the before/after of a image gen change can from the same config file defined in a repo.mflux-generate --model schnell --metadata --config-from-metadata <file from dev run>
- re-do the image gen, but using a diff model than the one that saved the configmflux-generate --model dev --metadata --config-from-metadata <file> --guidance 5.0
- re-genenerate, but change 1 variablemflux-generate --model dev --metadata --config-from-metadata <file> --quantize 4
- re-generate, but with the lighter quantized model