From 0812d6252c95f0498c46ab75d086555fa1064cbf Mon Sep 17 00:00:00 2001
From: Anthony Wu <462072+anthonywu@users.noreply.github.com>
Date: Mon, 16 Sep 2024 10:27:04 -0700
Subject: [PATCH 1/8] simplify import paths of frequently used items in scripts
and demos
---
README.md | 3 +--
src/mflux/__init__.py | 5 +++++
src/mflux/generate.py | 4 +---
src/mflux/save.py | 3 +--
tests/test_readme_example.sh | 7 +++++++
5 files changed, 15 insertions(+), 7 deletions(-)
create mode 100755 tests/test_readme_example.sh
diff --git a/README.md b/README.md
index 8fd15b0..3f5539f 100644
--- a/README.md
+++ b/README.md
@@ -105,8 +105,7 @@ mflux-generate --model dev --prompt "Luxury food photograph" --steps 25 --seed 2
Or, with the correct python environment active, create and run a separate script like the following:
```python
-from mflux.flux.flux import Flux1
-from mflux.config.config import Config
+from mflux import Flux1, Config
# Load the model
flux = Flux1.from_alias(
diff --git a/src/mflux/__init__.py b/src/mflux/__init__.py
index e69de29..3994351 100644
--- a/src/mflux/__init__.py
+++ b/src/mflux/__init__.py
@@ -0,0 +1,5 @@
+from mflux.flux.flux import Flux1
+from mflux.config.config import Config
+from mflux.config.model_config import ModelConfig
+
+__all__ = ["Flux1", "Config", "ModelConfig"]
diff --git a/src/mflux/generate.py b/src/mflux/generate.py
index 1b8e59f..e4a6640 100644
--- a/src/mflux/generate.py
+++ b/src/mflux/generate.py
@@ -5,9 +5,7 @@ import time
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
-from mflux.config.model_config import ModelConfig
-from mflux.config.config import Config
-from mflux.flux.flux import Flux1
+from mflux import Flux1, Config, ModelConfig
def main():
diff --git a/src/mflux/save.py b/src/mflux/save.py
index e34bf8f..0bfd4bd 100644
--- a/src/mflux/save.py
+++ b/src/mflux/save.py
@@ -4,8 +4,7 @@ import sys
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
-from mflux.flux.flux import Flux1
-from mflux.config.model_config import ModelConfig
+from mflux import Flux1, ModelConfig
def main():
diff --git a/tests/test_readme_example.sh b/tests/test_readme_example.sh
new file mode 100755
index 0000000..3fc6827
--- /dev/null
+++ b/tests/test_readme_example.sh
@@ -0,0 +1,7 @@
+mflux-generate \
+ --prompt "Luxury food photograph" \
+ --model schnell \
+ --steps 2 \
+ --seed 2 \
+ --height 1024 \
+ --width 1024
From 43618154d30f4e42d82a2f2faaaac13e37bfebf1 Mon Sep 17 00:00:00 2001
From: Anthony Wu <462072+anthonywu@users.noreply.github.com>
Date: Mon, 16 Sep 2024 15:04:30 -0700
Subject: [PATCH 2/8] remove apparently unnecessary import of the src/mflux
directory
---
src/mflux/generate.py | 2 --
src/mflux/save.py | 2 --
2 files changed, 4 deletions(-)
diff --git a/src/mflux/generate.py b/src/mflux/generate.py
index e4a6640..cbbb3da 100644
--- a/src/mflux/generate.py
+++ b/src/mflux/generate.py
@@ -3,8 +3,6 @@ import os
import sys
import time
-sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
-
from mflux import Flux1, Config, ModelConfig
diff --git a/src/mflux/save.py b/src/mflux/save.py
index 0bfd4bd..9be9439 100644
--- a/src/mflux/save.py
+++ b/src/mflux/save.py
@@ -2,8 +2,6 @@ import argparse
import os
import sys
-sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
-
from mflux import Flux1, ModelConfig
From 7cc2d4174dca089d6107a9096cb49055aa213ec0 Mon Sep 17 00:00:00 2001
From: Anthony Wu <462072+anthonywu@users.noreply.github.com>
Date: Thu, 19 Sep 2024 12:37:22 -0700
Subject: [PATCH 3/8] introduce Makefile with uv recommendation
---
Makefile | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 102 insertions(+)
create mode 100644 Makefile
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..d4376b0
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,102 @@
+# Makefile for mflux Python 3.10+ project, using 3.11 as recommended Python as of Sep 2024
+
+PYTHON_VERSION = 3.11
+VENV_DIR = .venv
+
+# Default target
+.PHONY: all
+all: install test
+
+.PHONY: expect-arm64
+expect-arm64:
+ # ๐ฅ๏ธ Checking for compatible machine
+ @if [ "$$(uname -m)" != "arm64" ]; then \
+ echo "mflux and MLX is not compatible with older Intel Macs. This project does not support your Mac."; \
+ exit 1; \
+ fi
+
+# we "expect" uv but should not install it for the user, let user *choose* to trust a third party installer
+.PHONY: expect-uv
+expect-uv:
+ @if ! /usr/bin/which -s uv; then \
+ echo "You can use classic python -m venv to setup this project, \nbut we officially support using uv for managing this project's environment.\n"; \
+ echo "Please install uv to continue:\n https://github.com/astral-sh/uv?tab=readme-ov-file#installation"; \
+ fi
+
+# assume reasonably that if user has installed uv, they trust ruff from the same team
+.PHONY: ensure-ruff
+ensure-ruff:
+ @if ! /usr/bin/which -s ruff; then \
+ echo "ruff required for code linting and formatting. Using uv tool to install ruff."; \
+ uv tool install ruff; \
+ fi
+
+# Create virtual environment with uv
+.PHONY: venv-init
+venv-init: expect-arm64 expect-uv
+ # ๐๏ธ Creating virtual environment with recommended uv tool:
+ uv python install --quiet $(PYTHON_VERSION)
+ uv venv --python $(PYTHON_VERSION)
+ # โ
"Python $(PYTHON_VERSION) Virtual environment created at $(VENV_DIR)"
+
+# Install dependencies
+.PHONY: install
+install: venv-init
+ # ๐๏ธ Installing dependencies...
+ uv pip install -e .
+ # โ
Dependencies installed.
+
+# Run linters
+.PHONY: lint
+lint: ensure-ruff
+ # ๐๏ธ Running linters, your files will not be mutated.
+ # Use 'make autofix' to auto-apply fixes."
+ ruff check
+ # โ
Linting complete."
+
+# Run formatter (if dev does not do so in their IDE)
+.PHONY: format
+format: ensure-ruff
+ # ๐๏ธ Running formatter, your files will be changed to comply to formatting configs.
+ ruff format
+ # display the summaries of diffs in repo, some of these diffs are generated by the formatter
+ git diff --stat
+ # โ
Formatting complete. Please review your git diffs, if any.
+
+# Run ruff auto lint and format
+# use || true to force possibly failing format/lint checks to allow rest of make helper to continue
+.PHONY: autofix
+autofix: ensure-ruff
+ # ๐๏ธ Running linter and formatters on files...
+ @(ruff format --respect-gitignore --target-version py310 || true)
+ # โ
auto formatting complete
+ @(ruff check --fix || true)
+ # โ
auto lint fixes complete, check for issues ruff cannot auto fix
+
+# Run tests
+.PHONY: test
+test:
+ # ๐๏ธ Running tests...
+ # mock success stub for future test suite ๐
+ @true
+ # โ
Tests completed
+
+# Clean up
+.PHONY: clean
+clean:
+ # ๐งผ Cleaning up venv.
+ rm -rf $(VENV_DIR)
+ # โ
Cleaned up venv. Run 'make install' to re-generate.
+
+# Help message
+.PHONY: help
+help:
+ @echo "mflux commands:"
+ @echo " make all - Set up the project and run tests"
+ @echo " make install - Install project dev dependencies"
+ @echo " make lint - Run ruff python linter"
+ @echo " make format - Run ruff code formatter"
+ @echo " make autofix - Run linters auto fixes *and* style formatter"
+ @echo " make test - Run tests"
+ @echo " make clean - Remove the virtual environment"
+ @echo " make help - Show this help message"
From d565807e5bf5352e136fcdb24b14f7c173047883 Mon Sep 17 00:00:00 2001
From: Anthony Wu <462072+anthonywu@users.noreply.github.com>
Date: Thu, 19 Sep 2024 12:48:06 -0700
Subject: [PATCH 4/8] update readme to match
---
README.md | 65 ++++++++++++++++++++++++++++---------------------------
1 file changed, 33 insertions(+), 32 deletions(-)
diff --git a/README.md b/README.md
index ab7398b..f02089b 100644
--- a/README.md
+++ b/README.md
@@ -23,48 +23,48 @@ like [Numpy](https://numpy.org) and [Pillow](https://pypi.org/project/pillow/) f
- [x] FLUX.1-Dev
### Installation
-For users, the easiest way to install MFLUX is to first create a new virtual environment to isolate dependencies:
- ```
- mkdir -p mflux && cd mflux && python3 -m venv .venv && source .venv/bin/activate
- ```
+For users, the easiest way to install MFLUX is to use `uv tool`:
+
+If you have [installed `uv`](https://github.com/astral-sh/uv?tab=readme-ov-file#installation), simply: `uv tool install mflux` to get the `mflux-generate` and related command line executables. You can skip to the usage guides below.
+
+
+For the classic way to create a user virtual environment:
+```
+mkdir -p mflux && cd mflux && python3 -m venv .venv && source .venv/bin/activate
+```
This creates and activates a virtual environment in the `mflux` folder. After that, install MFLUX via pip:
- ```
- pip install -U mflux
- ```
+```
+pip install -U mflux
+```
+
+
For contributors (click to expand)
1. Clone the repo:
- ```
+ ```sh
git clone git@github.com:filipstrand/mflux.git
```
-2. Navigate to the project and set up a virtual environment:
- ```
- cd mflux
- python3 -m venv .venv # alternative: `uv venv`
- source .venv/bin/activate
- ```
-3. Install the required dependencies in [development mode](https://setuptools.pypa.io/en/latest/userguide/development_mode.html) as defined in `pyproject.toml`:
- ```
- pip install -e .
- ```
-4. Follow format and lint checks prior to submitting Pull Requests. Install the `ruff` tool as a common resource somewhere else in your system external to this project.
- - [`uv tool install ruff`](https://github.com/astral-sh/uv) OR [`pipx install ruff`](https://github.com/pypa/pipx).
- - [`ruff check` and `ruff check --fix`](https://github.com/astral-sh/ruff?tab=readme-ov-file#usage) any linter warnings generated from your PR diff.
- - [`ruff format`](https://github.com/astral-sh/ruff?tab=readme-ov-file#usage) any added or modified files in your PR diff.
+2. `make install` and `make test` (and `make clean` for venv resets)
+3. Follow format and lint checks prior to submitting Pull Requests. The recommended `make lint` and `make format` installs and uses [`ruff`](https://github.com/astral-sh/ruff). You can setup your editor/IDE to lint/format automatically, or use our provided `make` helpers:
+ - `make format` - formats your code
+ - `make lint` - shows your lint errors and warnings, but does not auto fix
+ - `make autofix` - formats your code **and** attempts to auto fix lint errors
+ - consult official [`ruff` documentation](https://docs.astral.sh/ruff/) on advanced usages
+
### Generating an image
Run the command `mflux-generate` by specifying a prompt and the model and some optional arguments. For example, here we use a quantized version of the `schnell` model for 2 steps:
-```
+```sh
mflux-generate --model schnell --prompt "Luxury food photograph" --steps 2 --seed 2 -q 8
```
This example uses the more powerful `dev` model with 25 time steps:
-```
+```sh
mflux-generate --model dev --prompt "Luxury food photograph" --steps 25 --seed 2 -q 8
```
@@ -140,7 +140,7 @@ For more options on how to configure MFLUX, please see [generate.py](src/mflux/g
These numbers are based on the non-quantized `schnell` model, with the configuration provided in the code snippet below.
To time your machine, run the following:
-```
+```sh
time mflux-generate \
--prompt "Luxury food photograph" \
--model schnell \
@@ -219,7 +219,7 @@ Luxury food photograph of an italian Linguine pasta alle vongole dish with lots
MFLUX supports running FLUX in 4-bit or 8-bit quantized mode. Running a quantized version can greatly speed up the
generation process and reduce the memory consumption by several gigabytes. [Quantized models also take up less disk space](#size-comparisons-for-quantized-models).
-```
+```sh
mflux-generate \
--model schnell \
--steps 2 \
@@ -252,7 +252,7 @@ The reason weights sizes are not fully cut in half is because a small number of
To save a local copy of the quantized weights, run the `mflux-save` command like so:
-```
+```sh
mflux-save \
--path "/Users/filipstrand/Desktop/schnell_8bit" \
--model schnell \
@@ -265,7 +265,7 @@ mflux-save \
To generate a new image from the quantized model, simply provide a `--path` to where it was saved:
-```
+```sh
mflux-generate \
--path "/Users/filipstrand/Desktop/schnell_8bit" \
--model schnell \
@@ -290,7 +290,7 @@ In other words, you can reclaim the 34GB diskspace (per model) by deleting the f
MFLUX also supports running a non-quantized model directly from a custom location.
In the example below, the model is placed in `/Users/filipstrand/Desktop/schnell`:
-```
+```sh
mflux-generate \
--path "/Users/filipstrand/Desktop/schnell" \
--model schnell \
@@ -339,7 +339,7 @@ MFLUX support loading trained [LoRA](https://huggingface.co/docs/diffusers/en/tr
The following example [The_Hound](https://huggingface.co/TheLastBen/The_Hound) LoRA from [@TheLastBen](https://github.com/TheLastBen):
-```
+```sh
mflux-generate --prompt "sandor clegane" --model dev --steps 20 --seed 43 -q 8 --lora-paths "sandor_clegane_single_layer.safetensors"
```
@@ -348,7 +348,7 @@ mflux-generate --prompt "sandor clegane" --model dev --steps 20 --seed 43 -q 8 -
The following example is [Flux_1_Dev_LoRA_Paper-Cutout-Style](https://huggingface.co/Norod78/Flux_1_Dev_LoRA_Paper-Cutout-Style) LoRA from [@Norod78](https://huggingface.co/Norod78):
-```
+```sh
mflux-generate --prompt "pikachu, Paper Cutout Style" --model schnell --steps 4 --seed 43 -q 8 --lora-paths "Flux_1_Dev_LoRA_Paper-Cutout-Style.safetensors"
```

@@ -361,7 +361,7 @@ mflux-generate --prompt "pikachu, Paper Cutout Style" --model schnell --steps 4
Multiple LoRAs can be sent in to combine the effects of the individual adapters. The following example combines both of the above LoRAs:
-```
+```sh
mflux-generate \
--prompt "sandor clegane in a forest, Paper Cutout Style" \
--model dev \
@@ -399,5 +399,6 @@ To report additional formats, examples or other any suggestions related to LoRA
### TODO
+- [ ] Establish unit test suite
- [ ] LoRA fine-tuning
- [ ] Frontend support (Gradio/Streamlit/Other?)
From 5a7157e7e898dd87765bd999c0fb9f7966aa22ca Mon Sep 17 00:00:00 2001
From: filipstrand
Date: Sat, 21 Sep 2024 10:23:05 +0200
Subject: [PATCH 5/8] Simplify import paths for controlnet file
---
src/mflux/__init__.py | 7 +++++--
src/mflux/generate.py | 2 --
src/mflux/generate_controlnet.py | 9 +--------
3 files changed, 6 insertions(+), 12 deletions(-)
diff --git a/src/mflux/__init__.py b/src/mflux/__init__.py
index 3994351..9547ab8 100644
--- a/src/mflux/__init__.py
+++ b/src/mflux/__init__.py
@@ -1,5 +1,8 @@
-from mflux.flux.flux import Flux1
from mflux.config.config import Config
+from mflux.config.config import ConfigControlnet
from mflux.config.model_config import ModelConfig
+from mflux.controlnet.flux_controlnet import Flux1Controlnet
+from mflux.flux.flux import Flux1
+from mflux.post_processing.image_util import ImageUtil
-__all__ = ["Flux1", "Config", "ModelConfig"]
+__all__ = ["Flux1", "Flux1Controlnet", "Config", "ConfigControlnet", "ModelConfig", "ImageUtil"]
diff --git a/src/mflux/generate.py b/src/mflux/generate.py
index 6e3a4ae..fdcf8bd 100644
--- a/src/mflux/generate.py
+++ b/src/mflux/generate.py
@@ -1,6 +1,4 @@
import argparse
-import os
-import sys
import time
from mflux import Flux1, Config, ModelConfig
diff --git a/src/mflux/generate_controlnet.py b/src/mflux/generate_controlnet.py
index 4c5bb1a..2e0784b 100644
--- a/src/mflux/generate_controlnet.py
+++ b/src/mflux/generate_controlnet.py
@@ -1,14 +1,7 @@
import argparse
-import os
-import sys
import time
-sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
-
-from mflux.config.model_config import ModelConfig
-from mflux.config.config import ConfigControlnet
-from mflux.controlnet.flux_controlnet import Flux1Controlnet
-from mflux.post_processing.image_util import ImageUtil
+from mflux import Flux1Controlnet, ConfigControlnet, ModelConfig, ImageUtil
def main():
From c170e8997740c158166ec0f46a8fd58c20cbc025 Mon Sep 17 00:00:00 2001
From: filipstrand
Date: Sat, 21 Sep 2024 10:39:01 +0200
Subject: [PATCH 6/8] remove unnecessary imports
---
src/mflux/save.py | 2 --
1 file changed, 2 deletions(-)
diff --git a/src/mflux/save.py b/src/mflux/save.py
index 9be9439..49409ca 100644
--- a/src/mflux/save.py
+++ b/src/mflux/save.py
@@ -1,6 +1,4 @@
import argparse
-import os
-import sys
from mflux import Flux1, ModelConfig
From 557996049e86efba9987b7b57ef49ed439a4185e Mon Sep 17 00:00:00 2001
From: filipstrand
Date: Sat, 21 Sep 2024 10:46:00 +0200
Subject: [PATCH 7/8] Add newlines to fix markdown rendering
---
README.md | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/README.md b/README.md
index f02089b..2f05912 100644
--- a/README.md
+++ b/README.md
@@ -29,13 +29,17 @@ If you have [installed `uv`](https://github.com/astral-sh/uv?tab=readme-ov-file#
For the classic way to create a user virtual environment:
+
```
mkdir -p mflux && cd mflux && python3 -m venv .venv && source .venv/bin/activate
```
+
This creates and activates a virtual environment in the `mflux` folder. After that, install MFLUX via pip:
+
```
pip install -U mflux
```
+
From abd7893612c20c644ce89699550bc90dfe37d7d5 Mon Sep 17 00:00:00 2001
From: filipstrand
Date: Sat, 21 Sep 2024 14:36:09 +0200
Subject: [PATCH 8/8] Fix hidden_states in single_transformer_blocks for
controlnet transformer
---
src/mflux/controlnet/transformer_controlnet.py | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/src/mflux/controlnet/transformer_controlnet.py b/src/mflux/controlnet/transformer_controlnet.py
index 33bbe84..0406d8b 100644
--- a/src/mflux/controlnet/transformer_controlnet.py
+++ b/src/mflux/controlnet/transformer_controlnet.py
@@ -1,5 +1,3 @@
-from typing import Tuple
-
import mlx.core as mx
from mlx import nn
@@ -77,12 +75,12 @@ class TransformerControlnet(nn.Module):
single_block_samples = ()
for block in self.single_transformer_blocks:
- ctrlnet_hidden_states = block.forward(
- hidden_states=ctrlnet_hidden_states,
+ hidden_states = block.forward(
+ hidden_states=hidden_states,
text_embeddings=text_embeddings,
rotary_embeddings=image_rotary_emb
)
- single_block_samples = single_block_samples + (ctrlnet_hidden_states[:, encoder_hidden_states.shape[1] :],)
+ single_block_samples = single_block_samples + (hidden_states[:, encoder_hidden_states.shape[1]:],)
controlnet_single_block_samples = ()
for single_block_sample, controlnet_block in zip(single_block_samples, self.controlnet_single_blocks):