Skip to content

Conversation

@lstein
Copy link
Collaborator

@lstein lstein commented May 4, 2023

Application-wide configuration service

This PR creates a new InvokeAIAppConfig object that reads application-wide settings from an init file, the environment, and the command line.

Arguments and fields are taken from the pydantic definition of the model. Defaults can be set by creating a yaml configuration file that has a top-level key of "InvokeAI" and subheadings for each of the categories returned by invokeai --help.

The file looks like this:

[file: invokeai.yaml]

InvokeAI:
  Paths:
    root: /home/lstein/invokeai-main
    conf_path: configs/models.yaml
    legacy_conf_dir: configs/stable-diffusion
    outdir: outputs
    embedding_dir: embeddings
    lora_dir: loras
    autoconvert_dir: null
    gfpgan_model_dir: models/gfpgan/GFPGANv1.4.pth
  Models:
    model: stable-diffusion-1.5
    embeddings: true
  Memory/Performance:
    xformers_enabled: false
    sequential_guidance: false
    precision: float16
    max_loaded_models: 4
    always_use_cpu: false
    free_gpu_mem: false
  Features:
    nsfw_checker: true
    restore: true
    esrgan: true
    patchmatch: true
    internet_available: true
    log_tokenization: false
  Cross-Origin Resource Sharing:
    allow_origins: []
    allow_credentials: true
    allow_methods:
    - '*'
    allow_headers:
    - '*'
  Web Server:
    host: 127.0.0.1
    port: 8081

The default name of the configuration file is invokeai.yaml, located in INVOKEAI_ROOT. You can use any OmegaConf dictionary by passing it to the config object at initialization time:

 omegaconf = OmegaConf.load('/tmp/init.yaml')
 conf = InvokeAIAppConfig(conf=omegaconf)

The default name of the configuration file is invokeai.yaml, located in INVOKEAI_ROOT. You can replace supersede this by providing anyOmegaConf dictionary object initialization time:

omegaconf = OmegaConf.load('/tmp/init.yaml')
conf = InvokeAIAppConfig(conf=omegaconf)

By default, InvokeAIAppConfig will parse the contents of sys.argv at initialization time. You may pass a list of strings in the optional argv argument to use instead of the system argv:

conf = InvokeAIAppConfig(arg=['--xformers_enabled'])

It is also possible to set a value at initialization time. This value has highest priority.

conf = InvokeAIAppConfig(xformers_enabled=True)

Any setting can be overwritten by setting an environment variable of form: "INVOKEAI_", as in:

export INVOKEAI_port=8080

Order of precedence (from highest):

  1. initialization options
  2. command line options
  3. environment variable options
  4. config file options
  5. pydantic defaults

Typical usage:

from invokeai.app.services.config import InvokeAIAppConfig

# get global configuration and print its nsfw_checker value
conf = InvokeAIAppConfig()
print(conf.nsfw_checker)

Finally, the configuration object is able to recreate its (modified) yaml file, by calling its to_yaml() method:

conf = InvokeAIAppConfig(outdir='/tmp', port=8080)
print(conf.to_yaml())

Legacy code removal and porting

This PR replaces Globals with the InvokeAIAppConfig system throughout, and therefore removes the globals.py and args.py modules. It also removes generate and the legacy CLI. The old CLI and web servers are now gone.

I have ported the functionality of the configuration script, the model installer, and the merge and textual inversion scripts. The invokeai command will now launch invokeai-node-cli, and invokeai-web will launch the web server.

I have changed the continuous invocation tests to accommodate the new command syntax in invokeai-node-cli. As a convenience function, you can also pass invocations to invokeai-node-cli (or its alias invokeai) on the command line as as standard input:

invokeai-node-cli "t2i --positive_prompt 'banana sushi' --seed 42"
invokeai < invocation_commands.txt

Copy link
Contributor

@ebr ebr left a comment

Choose a reason for hiding this comment

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

I've made some suggestions in #3311 (now rebased on this branch) - @lstein, please take a look

@lstein lstein requested a review from ebr May 15, 2023 13:09
Lincoln Stein and others added 2 commits May 17, 2023 14:13
- invokeai-configure updated to work with new config system
- migrate invokeai.init to invokeai.yaml during configure
- replace legacy invokeai with invokeai-node-cli
- add ability to run an invocation directly from invokeai-node-cli command line
- update CI tests to work with new invokeai syntax
@lstein
Copy link
Collaborator Author

lstein commented May 17, 2023

@ebr It turned out that having different config objects for the client and web apps wasn't doing what I wanted. In fact InvokeAIWebConfig was only picking up the web-specific configuration (e.g. port), and was not inheriting the app configuration (e.g. embedding directory). So the web config is gone and merged with the app config.

However, I ended up generalizing the configuration categories, so they are nicely categorized now. The config file looks like this:

InvokeAI:
  Paths:
    root: /home/lstein/invokeai-main
    conf_path: configs/models.yaml
    legacy_conf_dir: configs/stable-diffusion
    outdir: outputs
    embedding_dir: embeddings
    lora_dir: loras
    autoconvert_dir: null
    gfpgan_model_dir: models/gfpgan/GFPGANv1.4.pth
  Models:
    model: stable-diffusion-1.5
    embeddings: true
  Memory/Performance:
    xformers_enabled: false
    sequential_guidance: false
    precision: float16
    max_loaded_models: 4
    always_use_cpu: false
    free_gpu_mem: false
  Features:
    nsfw_checker: true
    restore: true
    esrgan: true
    patchmatch: true
    internet_available: true
    log_tokenization: false
  Cross-Origin Resource Sharing:
    allow_origins: []
    allow_credentials: true
    allow_methods:
    - '*'
    allow_headers:
    - '*'
  Web Server:
    host: 127.0.0.1
    port: 8081

And the command-line help menu looks like this:

Paths:
  --root ROOT           InvokeAI runtime root directory
  --conf_path CONF_PATH
                        Path to models definition file
  --legacy_conf_dir LEGACY_CONF_DIR
                        Path to directory of legacy checkpoint config files
  --outdir OUTDIR       Default folder for output images
  --embedding_dir EMBEDDING_DIR
                        Path to InvokeAI textual inversion aembeddings directory
  --lora_dir LORA_DIR   Path to InvokeAI LoRA model directory
  --autoconvert_dir AUTOCONVERT_DIR
                        Path to a directory of ckpt files to be converted into diffusers and imported on startup.
  --gfpgan_model_dir GFPGAN_MODEL_DIR
                        Path to GFPGAN models directory.

Models:
  --model MODEL         Initial model name
  --embeddings, --no-embeddings
                        Load contents of embeddings directory (default: True)

Memory/Performance:
  --xformers_enabled, --no-xformers_enabled
                        Enable/disable memory-efficient attention (default: True)
  --sequential_guidance, --no-sequential_guidance
                        Whether to calculate guidance in serial instead of in parallel, lowering memory requirements (default: False)
  --precision {auto,float16,float32,autocast}
                        Floating point precision
  --max_loaded_models MAX_LOADED_MODELS
                        Maximum number of models to keep in memory for rapid switching
  --always_use_cpu, --no-always_use_cpu
                        If true, use the CPU for rendering even if a GPU is available. (default: False)
  --free_gpu_mem, --no-free_gpu_mem
                        If true, purge model from GPU after each generation. (default: False)

Features:
  --nsfw_checker, --no-nsfw_checker
                        Enable/disable the NSFW checker (default: True)
  --restore, --no-restore
                        Enable/disable face restoration code (default: True)
  --esrgan, --no-esrgan
                        Enable/disable upscaling code (default: True)
  --patchmatch, --no-patchmatch
                        Enable/disable patchmatch inpaint code (default: True)
  --internet_available, --no-internet_available
                        If true, attempt to download models on the fly; otherwise only use local models (default: True)
  --log_tokenization, --no-log_tokenization
                        Enable logging of parsed prompt tokens. (default: False)

Cross-Origin Resource Sharing:
  --allow_origins [ALLOW_ORIGINS ...]
                        Allowed CORS origins
  --allow_credentials, --no-allow_credentials
                        Allow CORS credentials (default: True)
  --allow_methods [ALLOW_METHODS ...]
                        Methods allowed for CORS
  --allow_headers [ALLOW_HEADERS ...]
                        Headers allowed for CORS

Web Server:
  --host HOST           IP address to bind to
  --port PORT           Port to bind to

Both the config file and the help text are driven off the pydantic class definition.

@ebr
Copy link
Contributor

ebr commented May 18, 2023

I pushed some commits containing web-related enhancements/cleanup, and one critical fix for a missing import.

All of the below works beautifully:

  • ✔️ config migration works
  • ✔️ running with uvicorn with autoreload works (e.g. uvicorn --reload invokeai.app.api_app:app --host 0.0.0.0 --port 19090)
  • ✔️ setting different port/host works as expected in all cases
  • ✔️ environment variables work, BUT see below re: case-sensitivity
  • ✔️ moved 'Cross-Origin Resource Sharing' stanza in the docstring to Web Server to match the actual category
  • ✔️ all other config file settings that I tested worked as expected

There are also some issues that in my opinion do NOT need to block this PR, but we can fix them in a followup to 3.0

  • config curses UI text overflows into the border on vertically short terminals
  • after running invokeai-configure to generate the new config file, max_loaded_models is a float, though it's correctly defined as an int in the schema. It seems to still be respected though, so it's a minor bug.
  • environment variables are case-sensitive, so INVOKEAI_HOST=0.0.0.0 does nothing, while INVOKEAI_host=0.0.0.0 works. This is very unexpected and I think we should change it.
  • there are still some references to Globals in realesrgan, textual_inversion, etc. (found with full-text search). I didn't fix those because not sure if those are slated for removal / refactoring, but just a heads-up.
  • I removed a legacy reference to hf_token that was only hit when running invokeai-configure --yes. It was breaking CI. This is no longer needed for installing the base models, and we can decide separately how to deal with this otherwise.

Note that for the Web UI to be served correctly with invokeai-web, we need to build a new UI dist. I tested this, but purposely avoided committing it to avoid messy conflicts with the currently ongoing work on the UI. Here's a Docker oneliner that does this build without needing to install the NodeJS toolchain locally (also note that it bypasses eslint because that fails for now):

# run from the repo root
docker run --rm -it --user $(id -u) --workdir /build -v ${PWD}/invokeai/frontend/web:/build node:18 bash -c "npm install --include dev; yarn vite build"

And to reset it back to current state (for a clean git worktree) just git checkout invokeai/frontend/web/dist

Copy link
Contributor

@ebr ebr left a comment

Choose a reason for hiding this comment

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

Approved, but please see above comment. I can open new issues for the minor concerns raised, or we can discuss in Discord how to handle any of those.

Overall, AMAZING work from all angles (structured config file, typed configuration, all the things!!) 👏 . And I love how much cleaner and succinct the configuration has become, removing so much legacy code. We wanted to retire Globals all the way last November 😄 - thank you for this!

@lstein
Copy link
Collaborator Author

lstein commented May 18, 2023

I pushed some commits containing web-related enhancements/cleanup, and one critical fix for a missing import.

All of the below works beautifully:

  • ✔️ config migration works
  • ✔️ running with uvicorn with autoreload works (e.g. uvicorn --reload invokeai.app.api_app:app --host 0.0.0.0 --port 19090)
  • ✔️ setting different port/host works as expected in all cases
  • ✔️ environment variables work, BUT see below re: case-sensitivity
  • ✔️ moved 'Cross-Origin Resource Sharing' stanza in the docstring to Web Server to match the actual category
  • ✔️ all other config file settings that I tested worked as expected

There are also some issues that in my opinion do NOT need to block this PR, but we can fix them in a followup to 3.0

  • config curses UI text overflows into the border on vertically short terminals
  • after running invokeai-configure to generate the new config file, max_loaded_models is a float, though it's correctly defined as an int in the schema. It seems to still be respected though, so it's a minor bug.
  • environment variables are case-sensitive, so INVOKEAI_HOST=0.0.0.0 does nothing, while INVOKEAI_host=0.0.0.0 works. This is very unexpected and I think we should change it.
  • there are still some references to Globals in realesrgan, textual_inversion, etc. (found with full-text search). I didn't fix those because not sure if those are slated for removal / refactoring, but just a heads-up.
  • I removed a legacy reference to hf_token that was only hit when running invokeai-configure --yes. It was breaking CI. This is no longer needed for installing the base models, and we can decide separately how to deal with this otherwise.

Note that for the Web UI to be served correctly with invokeai-web, we need to build a new UI dist. I tested this, but purposely avoided committing it to avoid messy conflicts with the currently ongoing work on the UI. Here's a Docker oneliner that does this build without needing to install the NodeJS toolchain locally (also note that it bypasses eslint because that fails for now):

# run from the repo root
docker run --rm -it --user $(id -u) --workdir /build -v ${PWD}/invokeai/frontend/web:/build node:18 bash -c "npm install --include dev; yarn vite build"

And to reset it back to current state (for a clean git worktree) just git checkout invokeai/frontend/web/dist

Thanks so much for the review! I will make the following changes:

  1. Fix environment variables to be case insensitive.
  2. Remove dangling Globals references in textual_inversion and other places. (Dang, thought I'd found 'em all)
  3. Fix the int<->float conversion in the configure script. I'd noticed this but was too lazy to fix.

I've got a problem with the CI tests. I want to feed commands to invoke-node-cli from standard input using the "<" shell operator, but GitHub tells me this is improper syntax (at least on windows). Is there an equivalent, or do I have to add a --from_infile argument?

Copy link
Contributor

@damian0815 damian0815 left a comment

Choose a reason for hiding this comment

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

looks good to me

- Make environment variable settings case InSenSiTive:
  INVOKEAI_MAX_LOADED_MODELS and InvokeAI_Max_Loaded_Models
  environment variables will both set `max_loaded_models`

- Updated realesrgan to use new config system.

- Updated textual_inversion_training to use new config system.

- Discovered a race condition when InvokeAIAppConfig is created
  at module load time, which makes it impossible to customize
  or replace the help message produced with --help on the command
  line. To fix this, moved all instances of get_invokeai_config()
  from module load time to object initialization time. Makes code
  cleaner, too.

- Added `--from_file` argument to `invokeai-node-cli` and changed
  github action to match. CI tests will hopefully work now.
@lstein lstein merged commit 7025c00 into main May 18, 2023
@lstein lstein deleted the lstein/global-configuration branch May 18, 2023 17:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants