Merge branch 'main' into development
- this syncs documentation and code
@ -1,4 +1,4 @@
|
||||
name: Test Dream with Conda
|
||||
name: Test Invoke with Conda
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
@ -9,7 +9,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ ubuntu-latest, macos-12 ]
|
||||
name: Test dream.py on ${{ matrix.os }} with conda
|
||||
name: Test invoke.py on ${{ matrix.os }} with conda
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- run: |
|
||||
@ -85,9 +85,9 @@ jobs:
|
||||
fi
|
||||
# Utterly hacky, but I don't know how else to do this
|
||||
if [[ ${{ github.ref }} == 'refs/heads/master' ]]; then
|
||||
time ${{ steps.vars.outputs.PYTHON_BIN }} scripts/dream.py --from_file tests/preflight_prompts.txt
|
||||
time ${{ steps.vars.outputs.PYTHON_BIN }} scripts/invoke.py --from_file tests/preflight_prompts.txt
|
||||
elif [[ ${{ github.ref }} == 'refs/heads/development' ]]; then
|
||||
time ${{ steps.vars.outputs.PYTHON_BIN }} scripts/dream.py --from_file tests/dev_prompts.txt
|
||||
time ${{ steps.vars.outputs.PYTHON_BIN }} scripts/invoke.py --from_file tests/dev_prompts.txt
|
||||
fi
|
||||
mkdir -p outputs/img-samples
|
||||
- name: Archive results
|
3
.gitignore
vendored
@ -196,3 +196,6 @@ checkpoints
|
||||
.vscode/
|
||||
gfpgan/
|
||||
models/ldm/stable-diffusion-v1/model.sha256
|
||||
|
||||
# GFPGAN model files
|
||||
gfpgan/
|
||||
|
32
README.md
@ -24,7 +24,7 @@ _This repository was formally known as lstein/stable-diffusion_
|
||||
[CI checks on dev badge]: https://flat.badgen.net/github/checks/invoke-ai/InvokeAI/development?label=CI%20status%20on%20dev&cache=900&icon=github
|
||||
[CI checks on dev link]: https://github.com/invoke-ai/InvokeAI/actions?query=branch%3Adevelopment
|
||||
[CI checks on main badge]: https://flat.badgen.net/github/checks/invoke-ai/InvokeAI/main?label=CI%20status%20on%20main&cache=900&icon=github
|
||||
[CI checks on main link]: https://github.com/invoke-ai/InvokeAI/actions/workflows/test-dream-conda.yml
|
||||
[CI checks on main link]: https://github.com/invoke-ai/InvokeAI/actions/workflows/test-invoke-conda.yml
|
||||
[discord badge]: https://flat.badgen.net/discord/members/ZmtBAhwWhy?icon=discord
|
||||
[discord link]: https://discord.gg/ZmtBAhwWhy
|
||||
[github forks badge]: https://flat.badgen.net/github/forks/invoke-ai/InvokeAI?icon=github
|
||||
@ -41,10 +41,13 @@ _This repository was formally known as lstein/stable-diffusion_
|
||||
[latest release link]: https://github.com/invoke-ai/InvokeAI/releases
|
||||
</div>
|
||||
|
||||
This is a fork of [CompVis/stable-diffusion](https://github.com/CompVis/stable-diffusion), the open
|
||||
source text-to-image generator. It provides a streamlined process with various new features and
|
||||
options to aid the image generation process. It runs on Windows, Mac and Linux machines, and runs on
|
||||
GPU cards with as little as 4 GB or RAM.
|
||||
This is a fork of
|
||||
[CompVis/stable-diffusion](https://github.com/CompVis/stable-diffusion),
|
||||
the open source text-to-image generator. It provides a streamlined
|
||||
process with various new features and options to aid the image
|
||||
generation process. It runs on Windows, Mac and Linux machines, with
|
||||
GPU cards with as little as 4 GB or RAM. It provides both a polished
|
||||
Web interface, and an easy-to-use command-line interface.
|
||||
|
||||
_Note: This fork is rapidly evolving. Please use the
|
||||
[Issues](https://github.com/invoke-ai/InvokeAI/issues) tab to report bugs and make feature
|
||||
@ -90,20 +93,26 @@ You wil need one of the following:
|
||||
|
||||
- At least 6 GB of free disk space for the machine learning model, Python, and all its dependencies.
|
||||
|
||||
#### Note
|
||||
**Note**
|
||||
|
||||
If you have a Nvidia 10xx series card (e.g. the 1080ti), please
|
||||
run the dream script in full-precision mode as shown below.
|
||||
|
||||
Similarly, specify full-precision mode on Apple M1 hardware.
|
||||
|
||||
Precision is auto configured based on the device. If however you encounter
|
||||
errors like 'expected type Float but found Half' or 'not implemented for Half'
|
||||
you can try starting `dream.py` with the `--precision=float32` flag:
|
||||
you can try starting `invoke.py` with the `--precision=float32` flag:
|
||||
|
||||
```bash
|
||||
(ldm) ~/stable-diffusion$ python scripts/dream.py --precision=float32
|
||||
(ldm) ~/stable-diffusion$ python scripts/invoke.py --precision=float32
|
||||
```
|
||||
|
||||
### Features
|
||||
|
||||
#### Major Features
|
||||
|
||||
- [Web Server](docs/features/WEB.md)
|
||||
- [Interactive Command Line Interface](docs/features/CLI.md)
|
||||
- [Image To Image](docs/features/IMG2IMG.md)
|
||||
- [Inpainting Support](docs/features/INPAINTING.md)
|
||||
@ -111,10 +120,9 @@ you can try starting `dream.py` with the `--precision=float32` flag:
|
||||
- [Upscaling, face-restoration and outpainting](docs/features/POSTPROCESS.md)
|
||||
- [Seamless Tiling](docs/features/OTHER.md#seamless-tiling)
|
||||
- [Google Colab](docs/features/OTHER.md#google-colab)
|
||||
- [Web Server](docs/features/WEB.md)
|
||||
- [Reading Prompts From File](docs/features/PROMPTS.md#reading-prompts-from-a-file)
|
||||
- [Shortcut: Reusing Seeds](docs/features/OTHER.md#shortcuts-reusing-seeds)
|
||||
- [Weighted Prompts](docs/features/PROMPTS.md#weighted-prompts)
|
||||
- [Prompt Blending](docs/features/PROMPTS.md#prompt-blending)
|
||||
- [Thresholding and Perlin Noise Initialization Options](/docs/features/OTHER.md#thresholding-and-perlin-noise-initialization-options)
|
||||
- [Negative/Unconditioned Prompts](docs/features/PROMPTS.md#negative-and-unconditioned-prompts)
|
||||
- [Variations](docs/features/VARIATIONS.md)
|
||||
@ -130,7 +138,7 @@ you can try starting `dream.py` with the `--precision=float32` flag:
|
||||
|
||||
- vNEXT (TODO 2022)
|
||||
|
||||
- Deprecated `--full_precision` / `-F`. Simply omit it and `dream.py` will auto
|
||||
- Deprecated `--full_precision` / `-F`. Simply omit it and `invoke.py` will auto
|
||||
configure. To switch away from auto use the new flag like `--precision=float32`.
|
||||
|
||||
- v1.14 (11 September 2022)
|
||||
@ -156,7 +164,7 @@ you can try starting `dream.py` with the `--precision=float32` flag:
|
||||
- A new configuration file scheme that allows new models (including upcoming
|
||||
stable-diffusion-v1.5) to be added without altering the code.
|
||||
([David Wager](https://github.com/maddavid12))
|
||||
- Can specify --grid on dream.py command line as the default.
|
||||
- Can specify --grid on invoke.py command line as the default.
|
||||
- Miscellaneous internal bug and stability fixes.
|
||||
- Works on M1 Apple hardware.
|
||||
- Multiple bug fixes.
|
||||
|
@ -12,9 +12,9 @@ from PIL import Image
|
||||
from uuid import uuid4
|
||||
from threading import Event
|
||||
|
||||
from ldm.dream.args import Args, APP_ID, APP_VERSION, calculate_init_img_hash
|
||||
from ldm.dream.pngwriter import PngWriter, retrieve_metadata
|
||||
from ldm.dream.conditioning import split_weighted_subprompts
|
||||
from ldm.invoke.args import Args, APP_ID, APP_VERSION, calculate_init_img_hash
|
||||
from ldm.invoke.pngwriter import PngWriter, retrieve_metadata
|
||||
from ldm.invoke.conditioning import split_weighted_subprompts
|
||||
|
||||
from backend.modules.parameters import parameters_to_command
|
||||
|
||||
@ -147,7 +147,7 @@ class InvokeAIWebServer:
|
||||
self.init_image_path = os.path.join(self.result_path, 'init-images/')
|
||||
self.mask_image_path = os.path.join(self.result_path, 'mask-images/')
|
||||
# txt log
|
||||
self.log_path = os.path.join(self.result_path, 'dream_log.txt')
|
||||
self.log_path = os.path.join(self.result_path, 'invoke_log.txt')
|
||||
# make all output paths
|
||||
[
|
||||
os.makedirs(path, exist_ok=True)
|
||||
|
@ -1,6 +1,6 @@
|
||||
import argparse
|
||||
import os
|
||||
from ldm.dream.args import PRECISION_CHOICES
|
||||
from ldm.invoke.args import PRECISION_CHOICES
|
||||
|
||||
|
||||
def create_cmd_parser():
|
||||
|
@ -15,7 +15,7 @@ SAMPLER_CHOICES = [
|
||||
|
||||
def parameters_to_command(params):
|
||||
"""
|
||||
Converts dict of parameters into a `dream.py` REPL command.
|
||||
Converts dict of parameters into a `invoke.py` REPL command.
|
||||
"""
|
||||
|
||||
switches = list()
|
||||
|
@ -30,10 +30,10 @@ from send2trash import send2trash
|
||||
|
||||
|
||||
from ldm.generate import Generate
|
||||
from ldm.dream.restoration import Restoration
|
||||
from ldm.dream.pngwriter import PngWriter, retrieve_metadata
|
||||
from ldm.dream.args import APP_ID, APP_VERSION, calculate_init_img_hash
|
||||
from ldm.dream.conditioning import split_weighted_subprompts
|
||||
from ldm.invoke.restoration import Restoration
|
||||
from ldm.invoke.pngwriter import PngWriter, retrieve_metadata
|
||||
from ldm.invoke.args import APP_ID, APP_VERSION, calculate_init_img_hash
|
||||
from ldm.invoke.conditioning import split_weighted_subprompts
|
||||
|
||||
from modules.parameters import parameters_to_command
|
||||
|
||||
@ -125,7 +125,7 @@ class CanceledException(Exception):
|
||||
|
||||
try:
|
||||
gfpgan, codeformer, esrgan = None, None, None
|
||||
from ldm.dream.restoration.base import Restoration
|
||||
from ldm.invoke.restoration.base import Restoration
|
||||
|
||||
restoration = Restoration()
|
||||
gfpgan, codeformer = restoration.load_face_restore_models()
|
||||
@ -164,7 +164,7 @@ init_image_path = os.path.join(result_path, "init-images/")
|
||||
mask_image_path = os.path.join(result_path, "mask-images/")
|
||||
|
||||
# txt log
|
||||
log_path = os.path.join(result_path, "dream_log.txt")
|
||||
log_path = os.path.join(result_path, "invoke_log.txt")
|
||||
|
||||
# make all output paths
|
||||
[
|
||||
|
@ -5,9 +5,9 @@
|
||||
- Supports a Google Colab notebook for a standalone server running on Google hardware [Arturo Mendivil](https://github.com/artmen1516)
|
||||
- WebUI supports GFPGAN/ESRGAN facial reconstruction and upscaling [Kevin Gibbons](https://github.com/bakkot)
|
||||
- WebUI supports incremental display of in-progress images during generation [Kevin Gibbons](https://github.com/bakkot)
|
||||
- Output directory can be specified on the dream> command line.
|
||||
- Output directory can be specified on the invoke> command line.
|
||||
- The grid was displaying duplicated images when not enough images to fill the final row [Muhammad Usama](https://github.com/SMUsamaShah)
|
||||
- Can specify --grid on dream.py command line as the default.
|
||||
- Can specify --grid on invoke.py command line as the default.
|
||||
- Miscellaneous internal bug and stability fixes.
|
||||
|
||||
---
|
||||
@ -16,13 +16,13 @@
|
||||
|
||||
- Improved file handling, including ability to read prompts from standard input.
|
||||
(kudos to [Yunsaki](https://github.com/yunsaki)
|
||||
- The web server is now integrated with the dream.py script. Invoke by adding --web to
|
||||
the dream.py command arguments.
|
||||
- The web server is now integrated with the invoke.py script. Invoke by adding --web to
|
||||
the invoke.py command arguments.
|
||||
- Face restoration and upscaling via GFPGAN and Real-ESGAN are now automatically
|
||||
enabled if the GFPGAN directory is located as a sibling to Stable Diffusion.
|
||||
VRAM requirements are modestly reduced. Thanks to both [Blessedcoolant](https://github.com/blessedcoolant) and
|
||||
[Oceanswave](https://github.com/oceanswave) for their work on this.
|
||||
- You can now swap samplers on the dream> command line. [Blessedcoolant](https://github.com/blessedcoolant)
|
||||
- You can now swap samplers on the invoke> command line. [Blessedcoolant](https://github.com/blessedcoolant)
|
||||
|
||||
---
|
||||
|
||||
@ -32,7 +32,7 @@
|
||||
- You now can specify a seed of -1 to use the previous image's seed, -2 to use the seed for the image generated before that, etc.
|
||||
Seed memory only extends back to the previous command, but will work on all images generated with the -n# switch.
|
||||
- Variant generation support temporarily disabled pending more general solution.
|
||||
- Created a feature branch named **yunsaki-morphing-dream** which adds experimental support for
|
||||
- Created a feature branch named **yunsaki-morphing-invoke** which adds experimental support for
|
||||
iteratively modifying the prompt and its parameters. Please see[ Pull Request #86](https://github.com/lstein/stable-diffusion/pull/86)
|
||||
for a synopsis of how this works. Note that when this feature is eventually added to the main branch, it will may be modified
|
||||
significantly.
|
||||
@ -57,7 +57,7 @@
|
||||
|
||||
## v1.08 (24 August 2022)
|
||||
|
||||
- Escape single quotes on the dream> command before trying to parse. This avoids
|
||||
- Escape single quotes on the invoke> command before trying to parse. This avoids
|
||||
parse errors.
|
||||
- Removed instruction to get Python3.8 as first step in Windows install.
|
||||
Anaconda3 does it for you.
|
||||
@ -94,7 +94,7 @@
|
||||
be regenerated with the indicated key
|
||||
|
||||
- It should no longer be possible for one image to overwrite another
|
||||
- You can use the "cd" and "pwd" commands at the dream> prompt to set and retrieve
|
||||
- You can use the "cd" and "pwd" commands at the invoke> prompt to set and retrieve
|
||||
the path of the output directory.
|
||||
|
||||
---
|
||||
@ -128,7 +128,7 @@
|
||||
- added k_lms sampling.
|
||||
**Please run "conda env update" to load the k_lms dependencies!!**
|
||||
- use half precision arithmetic by default, resulting in faster execution and lower memory requirements
|
||||
Pass argument --full_precision to dream.py to get slower but more accurate image generation
|
||||
Pass argument --full_precision to invoke.py to get slower but more accurate image generation
|
||||
|
||||
---
|
||||
|
||||
|
BIN
docs/assets/Lincoln-and-Parrot-512-transparent.png
Executable file
After Width: | Height: | Size: 284 KiB |
BIN
docs/assets/Lincoln-and-Parrot-512.png
Normal file
After Width: | Height: | Size: 252 KiB |
BIN
docs/assets/invoke-web-server-1.png
Normal file
After Width: | Height: | Size: 983 KiB |
BIN
docs/assets/invoke-web-server-2.png
Normal file
After Width: | Height: | Size: 101 KiB |
BIN
docs/assets/invoke-web-server-3.png
Normal file
After Width: | Height: | Size: 546 KiB |
BIN
docs/assets/invoke-web-server-4.png
Normal file
After Width: | Height: | Size: 336 KiB |
BIN
docs/assets/invoke-web-server-5.png
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
docs/assets/invoke-web-server-6.png
Normal file
After Width: | Height: | Size: 148 KiB |
BIN
docs/assets/invoke-web-server-7.png
Normal file
After Width: | Height: | Size: 637 KiB |
BIN
docs/assets/invoke-web-server-8.png
Normal file
After Width: | Height: | Size: 529 KiB |
BIN
docs/assets/invoke_web_server.png
Normal file
After Width: | Height: | Size: 989 KiB |
After Width: | Height: | Size: 501 KiB |
After Width: | Height: | Size: 473 KiB |
BIN
docs/assets/prompt-blending/blue-sphere-0.5-red-cube-0.5.png
Normal file
After Width: | Height: | Size: 618 KiB |
After Width: | Height: | Size: 557 KiB |
BIN
docs/assets/prompt-blending/blue-sphere-red-cube-hybrid.png
Normal file
After Width: | Height: | Size: 340 KiB |
@ -4,7 +4,7 @@ title: Changelog
|
||||
|
||||
# :octicons-log-16: Changelog
|
||||
|
||||
## v1.13 <small>(in process)</small>
|
||||
## v1.13
|
||||
|
||||
- Supports a Google Colab notebook for a standalone server running on Google
|
||||
hardware [Arturo Mendivil](https://github.com/artmen1516)
|
||||
@ -12,10 +12,10 @@ title: Changelog
|
||||
[Kevin Gibbons](https://github.com/bakkot)
|
||||
- WebUI supports incremental display of in-progress images during generation
|
||||
[Kevin Gibbons](https://github.com/bakkot)
|
||||
- Output directory can be specified on the dream> command line.
|
||||
- Output directory can be specified on the invoke> command line.
|
||||
- The grid was displaying duplicated images when not enough images to fill the
|
||||
final row [Muhammad Usama](https://github.com/SMUsamaShah)
|
||||
- Can specify --grid on dream.py command line as the default.
|
||||
- Can specify --grid on invoke.py command line as the default.
|
||||
- Miscellaneous internal bug and stability fixes.
|
||||
|
||||
---
|
||||
@ -24,14 +24,14 @@ title: Changelog
|
||||
|
||||
- Improved file handling, including ability to read prompts from standard input.
|
||||
(kudos to [Yunsaki](https://github.com/yunsaki)
|
||||
- The web server is now integrated with the dream.py script. Invoke by adding
|
||||
--web to the dream.py command arguments.
|
||||
- The web server is now integrated with the invoke.py script. Invoke by adding
|
||||
--web to the invoke.py command arguments.
|
||||
- Face restoration and upscaling via GFPGAN and Real-ESGAN are now automatically
|
||||
enabled if the GFPGAN directory is located as a sibling to Stable Diffusion.
|
||||
VRAM requirements are modestly reduced. Thanks to both
|
||||
[Blessedcoolant](https://github.com/blessedcoolant) and
|
||||
[Oceanswave](https://github.com/oceanswave) for their work on this.
|
||||
- You can now swap samplers on the dream> command line.
|
||||
- You can now swap samplers on the invoke> command line.
|
||||
[Blessedcoolant](https://github.com/blessedcoolant)
|
||||
|
||||
---
|
||||
@ -45,7 +45,7 @@ title: Changelog
|
||||
back to the previous command, but will work on all images generated with the
|
||||
-n# switch.
|
||||
- Variant generation support temporarily disabled pending more general solution.
|
||||
- Created a feature branch named **yunsaki-morphing-dream** which adds
|
||||
- Created a feature branch named **yunsaki-morphing-invoke** which adds
|
||||
experimental support for iteratively modifying the prompt and its parameters.
|
||||
Please
|
||||
see[ Pull Request #86](https://github.com/lstein/stable-diffusion/pull/86) for
|
||||
@ -75,7 +75,7 @@ title: Changelog
|
||||
|
||||
## v1.08 <small>(24 August 2022)</small>
|
||||
|
||||
- Escape single quotes on the dream> command before trying to parse. This avoids
|
||||
- Escape single quotes on the invoke> command before trying to parse. This avoids
|
||||
parse errors.
|
||||
- Removed instruction to get Python3.8 as first step in Windows install.
|
||||
Anaconda3 does it for you.
|
||||
@ -112,7 +112,7 @@ title: Changelog
|
||||
can be regenerated with the indicated key
|
||||
|
||||
- It should no longer be possible for one image to overwrite another
|
||||
- You can use the "cd" and "pwd" commands at the dream> prompt to set and
|
||||
- You can use the "cd" and "pwd" commands at the invoke> prompt to set and
|
||||
retrieve the path of the output directory.
|
||||
|
||||
## v1.04 <small>(22 August 2022 - after the drop)</small>
|
||||
@ -139,5 +139,5 @@ title: Changelog
|
||||
- added k_lms sampling. **Please run "conda env update -f environment.yaml" to
|
||||
load the k_lms dependencies!!**
|
||||
- use half precision arithmetic by default, resulting in faster execution and
|
||||
lower memory requirements Pass argument --full_precision to dream.py to get
|
||||
lower memory requirements Pass argument --full_precision to invoke.py to get
|
||||
slower but more accurate image generation
|
||||
|
@ -8,8 +8,8 @@ hide:
|
||||
|
||||
## **Interactive Command Line Interface**
|
||||
|
||||
The `dream.py` script, located in `scripts/dream.py`, provides an interactive
|
||||
interface to image generation similar to the "dream mothership" bot that Stable
|
||||
The `invoke.py` script, located in `scripts/dream.py`, provides an interactive
|
||||
interface to image generation similar to the "invoke mothership" bot that Stable
|
||||
AI provided on its Discord server.
|
||||
|
||||
Unlike the `txt2img.py` and `img2img.py` scripts provided in the original
|
||||
@ -34,21 +34,21 @@ The script is confirmed to work on Linux, Windows and Mac systems.
|
||||
currently rudimentary, but a much better replacement is on its way.
|
||||
|
||||
```bash
|
||||
(ldm) ~/stable-diffusion$ python3 ./scripts/dream.py
|
||||
(ldm) ~/stable-diffusion$ python3 ./scripts/invoke.py
|
||||
* Initializing, be patient...
|
||||
Loading model from models/ldm/text2img-large/model.ckpt
|
||||
(...more initialization messages...)
|
||||
|
||||
* Initialization done! Awaiting your command...
|
||||
dream> ashley judd riding a camel -n2 -s150
|
||||
invoke> ashley judd riding a camel -n2 -s150
|
||||
Outputs:
|
||||
outputs/img-samples/00009.png: "ashley judd riding a camel" -n2 -s150 -S 416354203
|
||||
outputs/img-samples/00010.png: "ashley judd riding a camel" -n2 -s150 -S 1362479620
|
||||
|
||||
dream> "there's a fly in my soup" -n6 -g
|
||||
invoke> "there's a fly in my soup" -n6 -g
|
||||
outputs/img-samples/00011.png: "there's a fly in my soup" -n6 -g -S 2685670268
|
||||
seeds for individual rows: [2685670268, 1216708065, 2335773498, 822223658, 714542046, 3395302430]
|
||||
dream> q
|
||||
invoke> q
|
||||
|
||||
# this shows how to retrieve the prompt stored in the saved image's metadata
|
||||
(ldm) ~/stable-diffusion$ python ./scripts/images2prompt.py outputs/img_samples/*.png
|
||||
@ -57,10 +57,10 @@ dream> q
|
||||
00011.png: "there's a fly in my soup" -n6 -g -S 2685670268
|
||||
```
|
||||
|
||||

|
||||

|
||||
|
||||
The `dream>` prompt's arguments are pretty much identical to those used in the
|
||||
Discord bot, except you don't need to type "!dream" (it doesn't hurt if you do).
|
||||
The `invoke>` prompt's arguments are pretty much identical to those used in the
|
||||
Discord bot, except you don't need to type "!invoke" (it doesn't hurt if you do).
|
||||
A significant change is that creation of individual images is now the default
|
||||
unless `--grid` (`-g`) is given. A full list is given in
|
||||
[List of prompt arguments](#list-of-prompt-arguments).
|
||||
@ -73,7 +73,7 @@ the location of the model weight files.
|
||||
|
||||
### List of arguments recognized at the command line
|
||||
|
||||
These command-line arguments can be passed to `dream.py` when you first run it
|
||||
These command-line arguments can be passed to `invoke.py` when you first run it
|
||||
from the Windows, Mac or Linux command line. Some set defaults that can be
|
||||
overridden on a per-prompt basis (see [List of prompt arguments]
|
||||
(#list-of-prompt-arguments). Others
|
||||
@ -112,15 +112,15 @@ These arguments are deprecated but still work:
|
||||
| --laion400m | -l | False | Use older LAION400m weights; use `--model=laion400m` instead |
|
||||
|
||||
**A note on path names:** On Windows systems, you may run into
|
||||
problems when passing the dream script standard backslashed path
|
||||
problems when passing the invoke script standard backslashed path
|
||||
names because the Python interpreter treats "\" as an escape.
|
||||
You can either double your slashes (ick): C:\\\\path\\\\to\\\\my\\\\file, or
|
||||
use Linux/Mac style forward slashes (better): C:/path/to/my/file.
|
||||
|
||||
## List of prompt arguments
|
||||
|
||||
After the dream.py script initializes, it will present you with a
|
||||
**dream>** prompt. Here you can enter information to generate images
|
||||
After the invoke.py script initializes, it will present you with a
|
||||
**invoke>** prompt. Here you can enter information to generate images
|
||||
from text (txt2img), to embellish an existing image or sketch
|
||||
(img2img), or to selectively alter chosen regions of the image
|
||||
(inpainting).
|
||||
@ -128,13 +128,13 @@ from text (txt2img), to embellish an existing image or sketch
|
||||
### This is an example of txt2img:
|
||||
|
||||
~~~~
|
||||
dream> waterfall and rainbow -W640 -H480
|
||||
invoke> waterfall and rainbow -W640 -H480
|
||||
~~~~
|
||||
|
||||
This will create the requested image with the dimensions 640 (width)
|
||||
and 480 (height).
|
||||
|
||||
Here are the dream> command that apply to txt2img:
|
||||
Here are the invoke> command that apply to txt2img:
|
||||
|
||||
| Argument | Shortcut | Default | Description |
|
||||
|--------------------|------------|---------------------|--------------|
|
||||
@ -167,7 +167,7 @@ the nearest multiple of 64.
|
||||
### This is an example of img2img:
|
||||
|
||||
~~~~
|
||||
dream> waterfall and rainbow -I./vacation-photo.png -W640 -H480 --fit
|
||||
invoke> waterfall and rainbow -I./vacation-photo.png -W640 -H480 --fit
|
||||
~~~~
|
||||
|
||||
This will modify the indicated vacation photograph by making it more
|
||||
@ -188,7 +188,7 @@ accepts additional options:
|
||||
### This is an example of inpainting:
|
||||
|
||||
~~~~
|
||||
dream> waterfall and rainbow -I./vacation-photo.png -M./vacation-mask.png -W640 -H480 --fit
|
||||
invoke> waterfall and rainbow -I./vacation-photo.png -M./vacation-mask.png -W640 -H480 --fit
|
||||
~~~~
|
||||
|
||||
This will do the same thing as img2img, but image alterations will
|
||||
@ -224,20 +224,20 @@ Some examples:
|
||||
|
||||
Upscale to 4X its original size and fix faces using codeformer:
|
||||
~~~
|
||||
dream> !fix 0000045.4829112.png -G1 -U4 -ft codeformer
|
||||
invoke> !fix 0000045.4829112.png -G1 -U4 -ft codeformer
|
||||
~~~
|
||||
|
||||
Use the GFPGAN algorithm to fix faces, then upscale to 3X using --embiggen:
|
||||
|
||||
~~~
|
||||
dream> !fix 0000045.4829112.png -G0.8 -ft gfpgan
|
||||
invoke> !fix 0000045.4829112.png -G0.8 -ft gfpgan
|
||||
>> fixing outputs/img-samples/0000045.4829112.png
|
||||
>> retrieved seed 4829112 and prompt "boy enjoying a banana split"
|
||||
>> GFPGAN - Restoring Faces for image seed:4829112
|
||||
Outputs:
|
||||
[1] outputs/img-samples/000017.4829112.gfpgan-00.png: !fix "outputs/img-samples/0000045.4829112.png" -s 50 -S -W 512 -H 512 -C 7.5 -A k_lms -G 0.8
|
||||
|
||||
dream> !fix 000017.4829112.gfpgan-00.png --embiggen 3
|
||||
invoke> !fix 000017.4829112.gfpgan-00.png --embiggen 3
|
||||
...lots of text...
|
||||
Outputs:
|
||||
[2] outputs/img-samples/000018.2273800735.embiggen-00.png: !fix "outputs/img-samples/000017.243781548.gfpgan-00.png" -s 50 -S 2273800735 -W 512 -H 512 -C 7.5 -A k_lms --embiggen 3.0 0.75 0.25
|
||||
@ -251,9 +251,9 @@ provide either the name of a file in the current output directory, or
|
||||
a full file path.
|
||||
|
||||
~~~
|
||||
dream> !fetch 0000015.8929913.png
|
||||
invoke> !fetch 0000015.8929913.png
|
||||
# the script returns the next line, ready for editing and running:
|
||||
dream> a fantastic alien landscape -W 576 -H 512 -s 60 -A plms -C 7.5
|
||||
invoke> a fantastic alien landscape -W 576 -H 512 -s 60 -A plms -C 7.5
|
||||
~~~
|
||||
|
||||
Note that this command may behave unexpectedly if given a PNG file that
|
||||
@ -261,7 +261,7 @@ was not generated by InvokeAI.
|
||||
|
||||
## !history
|
||||
|
||||
The dream script keeps track of all the commands you issue during a
|
||||
The invoke script keeps track of all the commands you issue during a
|
||||
session, allowing you to re-run them. On Mac and Linux systems, it
|
||||
also writes the command-line history out to disk, giving you access to
|
||||
the most recent 1000 commands issued.
|
||||
@ -272,7 +272,7 @@ issued during the session (Windows), or the most recent 1000 commands
|
||||
where "NNN" is the history line number. For example:
|
||||
|
||||
~~~
|
||||
dream> !history
|
||||
invoke> !history
|
||||
...
|
||||
[14] happy woman sitting under tree wearing broad hat and flowing garment
|
||||
[15] beautiful woman sitting under tree wearing broad hat and flowing garment
|
||||
@ -280,8 +280,8 @@ dream> !history
|
||||
[20] watercolor of beautiful woman sitting under tree wearing broad hat and flowing garment -v0.2 -n6 -S2878767194
|
||||
[21] surrealist painting of beautiful woman sitting under tree wearing broad hat and flowing garment -v0.2 -n6 -S2878767194
|
||||
...
|
||||
dream> !20
|
||||
dream> watercolor of beautiful woman sitting under tree wearing broad hat and flowing garment -v0.2 -n6 -S2878767194
|
||||
invoke> !20
|
||||
invoke> watercolor of beautiful woman sitting under tree wearing broad hat and flowing garment -v0.2 -n6 -S2878767194
|
||||
~~~
|
||||
|
||||
## !search <search string>
|
||||
@ -290,7 +290,7 @@ This is similar to !history but it only returns lines that contain
|
||||
`search string`. For example:
|
||||
|
||||
~~~
|
||||
dream> !search surreal
|
||||
invoke> !search surreal
|
||||
[21] surrealist painting of beautiful woman sitting under tree wearing broad hat and flowing garment -v0.2 -n6 -S2878767194
|
||||
~~~
|
||||
|
||||
@ -312,16 +312,16 @@ command completion.
|
||||
- To paste a cut section back in, position the cursor where you want to paste, and type CTRL-Y
|
||||
|
||||
Windows users can get similar, but more limited, functionality if they
|
||||
launch dream.py with the "winpty" program and have the `pyreadline3`
|
||||
launch invoke.py with the "winpty" program and have the `pyreadline3`
|
||||
library installed:
|
||||
|
||||
~~~
|
||||
> winpty python scripts\dream.py
|
||||
> winpty python scripts\invoke.py
|
||||
~~~
|
||||
|
||||
On the Mac and Linux platforms, when you exit dream.py, the last 1000
|
||||
On the Mac and Linux platforms, when you exit invoke.py, the last 1000
|
||||
lines of your command-line history will be saved. When you restart
|
||||
dream.py, you can access the saved history using the up-arrow key.
|
||||
invoke.py, you can access the saved history using the up-arrow key.
|
||||
|
||||
In addition, limited command-line completion is installed. In various
|
||||
contexts, you can start typing your command and press tab. A list of
|
||||
@ -334,7 +334,7 @@ will attempt to complete pathnames for you. This is most handy for the
|
||||
the path with a slash ("/") or "./". For example:
|
||||
|
||||
~~~
|
||||
dream> zebra with a mustache -I./test-pictures<TAB>
|
||||
invoke> zebra with a mustache -I./test-pictures<TAB>
|
||||
-I./test-pictures/Lincoln-and-Parrot.png -I./test-pictures/zebra.jpg -I./test-pictures/madonna.png
|
||||
-I./test-pictures/bad-sketch.png -I./test-pictures/man_with_eagle/
|
||||
```
|
||||
|
@ -106,8 +106,8 @@ Running Embiggen with 512x512 tiles on an existing image, scaling up by a factor
|
||||
and doing the same again (default ESRGAN strength is 0.75, default overlap between tiles is 0.25):
|
||||
|
||||
```bash
|
||||
dream > a photo of a forest at sunset -s 100 -W 512 -H 512 -I outputs/forest.png -f 0.4 -embiggen 2.5
|
||||
dream > a photo of a forest at sunset -s 100 -W 512 -H 512 -I outputs/forest.png -f 0.4 -embiggen 2.5 0.75 0.25
|
||||
invoke > a photo of a forest at sunset -s 100 -W 512 -H 512 -I outputs/forest.png -f 0.4 -embiggen 2.5
|
||||
invoke > a photo of a forest at sunset -s 100 -W 512 -H 512 -I outputs/forest.png -f 0.4 -embiggen 2.5 0.75 0.25
|
||||
```
|
||||
|
||||
If your starting image was also 512x512 this should have taken 9 tiles.
|
||||
@ -118,7 +118,7 @@ If there weren't enough clouds in the sky of that forest you just made
|
||||
tiles:
|
||||
|
||||
```bash
|
||||
dream> a photo of puffy clouds over a forest at sunset -s 100 -W 512 -H 512 -I outputs/000002.seed.png -f 0.5 -embiggen_tiles 1 2 3
|
||||
invoke> a photo of puffy clouds over a forest at sunset -s 100 -W 512 -H 512 -I outputs/000002.seed.png -f 0.5 -embiggen_tiles 1 2 3
|
||||
```
|
||||
|
||||
## Fixing Previously-Generated Images
|
||||
@ -129,7 +129,7 @@ syntax `!fix path/to/file.png <embiggen>`. For example, you can rewrite the
|
||||
previous command to look like this:
|
||||
|
||||
~~~~
|
||||
dream> !fix ./outputs/000002.seed.png -embiggen_tiles 1 2 3
|
||||
invoke> !fix ./outputs/000002.seed.png -embiggen_tiles 1 2 3
|
||||
~~~~
|
||||
|
||||
A new file named `000002.seed.fixed.png` will be created in the output directory. Note that
|
||||
|
@ -10,18 +10,39 @@ top of the image you provide, preserving the original's basic shape and layout.
|
||||
the `--init_img` option as shown here:
|
||||
|
||||
```commandline
|
||||
dream> "waterfall and rainbow" --init_img=./init-images/crude_drawing.png --strength=0.5 -s100 -n4
|
||||
tree on a hill with a river, nature photograph, national geographic -I./test-pictures/tree-and-river-sketch.png -f 0.85
|
||||
```
|
||||
|
||||
This will take the original image shown here:
|
||||
|
||||
<img src="https://user-images.githubusercontent.com/50542132/193946000-c42a96d8-5a74-4f8a-b4c3-5213e6cadcce.png" width=350>
|
||||
|
||||
and generate a new image based on it as shown here:
|
||||
|
||||
<img src="https://user-images.githubusercontent.com/111189/194135515-53d4c060-e994-4016-8121-7c685e281ac9.png" width=350>
|
||||
|
||||
The `--init_img (-I)` option gives the path to the seed picture. `--strength (-f)` controls how much
|
||||
the original will be modified, ranging from `0.0` (keep the original intact), to `1.0` (ignore the
|
||||
original completely). The default is `0.75`, and ranges from `0.25-0.75` give interesting results.
|
||||
original completely). The default is `0.75`, and ranges from `0.25-0.90` give interesting results.
|
||||
Other relevant options include `-C` (classification free guidance scale), and `-s` (steps). Unlike `txt2img`,
|
||||
adding steps will continuously change the resulting image and it will not converge.
|
||||
|
||||
You may also pass a `-v<variation_amount>` option to generate `-n<iterations>` count variants on
|
||||
the original image. This is done by passing the first generated image
|
||||
back into img2img the requested number of times. It generates
|
||||
interesting variants.
|
||||
|
||||
Note that the prompt makes a big difference. For example, this slight variation on the prompt produces
|
||||
a very different image:
|
||||
|
||||
`photograph of a tree on a hill with a river`
|
||||
|
||||
<img src="https://user-images.githubusercontent.com/111189/194135220-16b62181-b60c-4248-8989-4834a8fd7fbd.png" width=350>
|
||||
|
||||
(When designing prompts, think about how the images scraped from the internet were captioned. Very few photographs will
|
||||
be labeled "photograph" or "photorealistic." They will, however, be captioned with the publication, photographer, camera
|
||||
model, or film settings.)
|
||||
|
||||
If the initial image contains transparent regions, then Stable Diffusion will only draw within the
|
||||
transparent regions, a process called "inpainting". However, for this to work correctly, the color
|
||||
information underneath the transparent needs to be preserved, not erased.
|
||||
@ -29,6 +50,17 @@ information underneath the transparent needs to be preserved, not erased.
|
||||
More details can be found here:
|
||||
[Creating Transparent Images For Inpainting](./INPAINTING.md#creating-transparent-regions-for-inpainting)
|
||||
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
**IMPORTANT ISSUE** `img2img` does not work properly on initial images smaller than 512x512. Please scale your
|
||||
image to at least 512x512 before using it. Larger images are not a problem, but may run out of VRAM on your
|
||||
GPU card. To fix this, use the --fit option, which downscales the initial image to fit within the box specified
|
||||
by width x height:
|
||||
~~~
|
||||
tree on a hill with a river, national geographic -I./test-pictures/big-sketch.png -H512 -W512 --fit
|
||||
~~~
|
||||
|
||||
>>>>>>> main
|
||||
## How does it actually work, though?
|
||||
|
||||
The main difference between `img2img` and `prompt2img` is the starting point. While `prompt2img` always starts with pure
|
||||
@ -38,7 +70,11 @@ gaussian noise and progressively refines it over the requested number of steps,
|
||||
**Let's start** by thinking about vanilla `prompt2img`, just generating an image from a prompt. If the step count is 10, then the "latent space" (Stable Diffusion's internal representation of the image) for the prompt "fire" with seed `1592514025` develops something like this:
|
||||
|
||||
```commandline
|
||||
<<<<<<< HEAD
|
||||
dream> "fire" -s10 -W384 -H384 -S1592514025
|
||||
=======
|
||||
invoke> "fire" -s10 -W384 -H384 -S1592514025
|
||||
>>>>>>> main
|
||||
```
|
||||
|
||||

|
||||
@ -66,7 +102,11 @@ Notice how much more fuzzy the starting image is for strength `0.7` compared to
|
||||
| | strength = 0.7 | strength = 0.4 |
|
||||
| -- | -- | -- |
|
||||
| initial image that SD sees |  |  |
|
||||
<<<<<<< HEAD
|
||||
| steps argument to `dream>` | `-S10` | `-S10` |
|
||||
=======
|
||||
| steps argument to `invoke>` | `-S10` | `-S10` |
|
||||
>>>>>>> main
|
||||
| steps actually taken | 7 | 4 |
|
||||
| latent space at each step |  |  |
|
||||
| output |  |  |
|
||||
@ -77,10 +117,17 @@ Both of the outputs look kind of like what I was thinking of. With the strength
|
||||
If you want to try this out yourself, all of these are using a seed of `1592514025` with a width/height of `384`, step count `10`, the default sampler (`k_lms`), and the single-word prompt `fire`:
|
||||
|
||||
```commandline
|
||||
<<<<<<< HEAD
|
||||
dream> "fire" -s10 -W384 -H384 -S1592514025 -I /tmp/fire-drawing.png --strength 0.7
|
||||
```
|
||||
|
||||
The code for rendering intermediates is on my (damian0815's) branch [document-img2img](https://github.com/damian0815/InvokeAI/tree/document-img2img) - run `dream.py` and check your `outputs/img-samples/intermediates` folder while generating an image.
|
||||
=======
|
||||
invoke> "fire" -s10 -W384 -H384 -S1592514025 -I /tmp/fire-drawing.png --strength 0.7
|
||||
```
|
||||
|
||||
The code for rendering intermediates is on my (damian0815's) branch [document-img2img](https://github.com/damian0815/InvokeAI/tree/document-img2img) - run `invoke.py` and check your `outputs/img-samples/intermediates` folder while generating an image.
|
||||
>>>>>>> main
|
||||
|
||||
### Compensating for the reduced step count
|
||||
|
||||
@ -89,7 +136,11 @@ After putting this guide together I was curious to see how the difference would
|
||||
Here's strength `0.4` (note step count `50`, which is `20 ÷ 0.4` to make sure SD does `20` steps from my image):
|
||||
|
||||
```commandline
|
||||
<<<<<<< HEAD
|
||||
dream> "fire" -s50 -W384 -H384 -S1592514025 -I /tmp/fire-drawing.png -f 0.4
|
||||
=======
|
||||
invoke> "fire" -s50 -W384 -H384 -S1592514025 -I /tmp/fire-drawing.png -f 0.4
|
||||
>>>>>>> main
|
||||
```
|
||||
|
||||

|
||||
@ -97,7 +148,11 @@ dream> "fire" -s50 -W384 -H384 -S1592514025 -I /tmp/fire-drawing.png -f 0.4
|
||||
and strength `0.7` (note step count `30`, which is roughly `20 ÷ 0.7` to make sure SD does `20` steps from my image):
|
||||
|
||||
```commandline
|
||||
<<<<<<< HEAD
|
||||
dream> "fire" -s30 -W384 -H384 -S1592514025 -I /tmp/fire-drawing.png -f 0.7
|
||||
=======
|
||||
invoke> "fire" -s30 -W384 -H384 -S1592514025 -I /tmp/fire-drawing.png -f 0.7
|
||||
>>>>>>> main
|
||||
```
|
||||
|
||||

|
||||
|
@ -8,7 +8,7 @@ title: Inpainting
|
||||
|
||||
Inpainting is really cool. To do it, you start with an initial image and use a photoeditor to make
|
||||
one or more regions transparent (i.e. they have a "hole" in them). You then provide the path to this
|
||||
image at the dream> command line using the `-I` switch. Stable Diffusion will only paint within the
|
||||
image at the invoke> command line using the `-I` switch. Stable Diffusion will only paint within the
|
||||
transparent region.
|
||||
|
||||
There's a catch. In the current implementation, you have to prepare the initial image correctly so
|
||||
@ -17,13 +17,13 @@ applications will by default erase the color information under the transparent p
|
||||
them with white or black, which will lead to suboptimal inpainting. You also must take care to
|
||||
export the PNG file in such a way that the color information is preserved.
|
||||
|
||||
If your photoeditor is erasing the underlying color information, `dream.py` will give you a big fat
|
||||
If your photoeditor is erasing the underlying color information, `invoke.py` will give you a big fat
|
||||
warning. If you can't find a way to coax your photoeditor to retain color values under transparent
|
||||
areas, then you can combine the `-I` and `-M` switches to provide both the original unedited image
|
||||
and the masked (partially transparent) image:
|
||||
|
||||
```bash
|
||||
dream> "man with cat on shoulder" -I./images/man.png -M./images/man-transparent.png
|
||||
invoke> "man with cat on shoulder" -I./images/man.png -M./images/man-transparent.png
|
||||
```
|
||||
|
||||
We are hoping to get rid of the need for this workaround in an upcoming release.
|
||||
@ -38,8 +38,8 @@ We are hoping to get rid of the need for this workaround in an upcoming release.
|
||||
2. Layer->Transparency->Add Alpha Channel
|
||||
3. Use lasoo tool to select region to mask
|
||||
4. Choose Select -> Float to create a floating selection
|
||||
5. Open the Layers toolbar (++ctrl+l++) and select "Floating Selection"
|
||||
6. Set opacity to 0%
|
||||
5. Open the Layers toolbar (^L) and select "Floating Selection"
|
||||
6. Set opacity to a value between 0% and 99%
|
||||
7. Export as PNG
|
||||
8. In the export dialogue, Make sure the "Save colour values from
|
||||
transparent pixels" checkbox is selected.
|
||||
@ -69,7 +69,7 @@ We are hoping to get rid of the need for this workaround in an upcoming release.
|
||||
|
||||

|
||||
|
||||
7. After following the inpainting instructions above (either through the CLI or the Web UI), marvel at your newfound ability to selectively dream. Lookin' good!
|
||||
7. After following the inpainting instructions above (either through the CLI or the Web UI), marvel at your newfound ability to selectively invoke. Lookin' good!
|
||||
|
||||

|
||||
|
||||
|
@ -22,10 +22,10 @@ Output Example: 
|
||||
|
||||
The seamless tiling mode causes generated images to seamlessly tile with itself. To use it, add the
|
||||
`--seamless` option when starting the script which will result in all generated images to tile, or
|
||||
for each `dream>` prompt as shown here:
|
||||
for each `invoke>` prompt as shown here:
|
||||
|
||||
```python
|
||||
dream> "pond garden with lotus by claude monet" --seamless -s100 -n4
|
||||
invoke> "pond garden with lotus by claude monet" --seamless -s100 -n4
|
||||
```
|
||||
|
||||
---
|
||||
@ -42,12 +42,12 @@ Here's an example of using this to do a quick refinement. It also illustrates us
|
||||
switch to turn on upscaling and face enhancement (see previous section):
|
||||
|
||||
```bash
|
||||
dream> a cute child playing hopscotch -G0.5
|
||||
invoke> a cute child playing hopscotch -G0.5
|
||||
[...]
|
||||
outputs/img-samples/000039.3498014304.png: "a cute child playing hopscotch" -s50 -W512 -H512 -C7.5 -mk_lms -S3498014304
|
||||
|
||||
# I wonder what it will look like if I bump up the steps and set facial enhancement to full strength?
|
||||
dream> a cute child playing hopscotch -G1.0 -s100 -S -1
|
||||
invoke> a cute child playing hopscotch -G1.0 -s100 -S -1
|
||||
reusing previous seed 3498014304
|
||||
[...]
|
||||
outputs/img-samples/000040.3498014304.png: "a cute child playing hopscotch" -G1.0 -s100 -W512 -H512 -C7.5 -mk_lms -S3498014304
|
||||
|
@ -31,7 +31,7 @@ Pretty nice, but it's annoying that the top of her head is cut
|
||||
off. She's also a bit off center. Let's fix that!
|
||||
|
||||
~~~~
|
||||
dream> !fix images/curly.png --outcrop top 64 right 64
|
||||
invoke> !fix images/curly.png --outcrop top 64 right 64
|
||||
~~~~
|
||||
|
||||
This is saying to apply the `outcrop` extension by extending the top
|
||||
@ -67,7 +67,7 @@ differences. Starting with the same image, here is how we would add an
|
||||
additional 64 pixels to the top of the image:
|
||||
|
||||
~~~
|
||||
dream> !fix images/curly.png --out_direction top 64
|
||||
invoke> !fix images/curly.png --out_direction top 64
|
||||
~~~
|
||||
|
||||
(you can abbreviate ``--out_direction` as `-D`.
|
||||
|
@ -20,39 +20,33 @@ The default face restoration module is GFPGAN. The default upscale is
|
||||
Real-ESRGAN. For an alternative face restoration module, see [CodeFormer
|
||||
Support] below.
|
||||
|
||||
As of version 1.14, environment.yaml will install the Real-ESRGAN package into
|
||||
the standard install location for python packages, and will put GFPGAN into a
|
||||
subdirectory of "src" in the InvokeAI directory. (The reason for this is
|
||||
that the standard GFPGAN distribution has a minor bug that adversely affects
|
||||
image color.) Upscaling with Real-ESRGAN should "just work" without further
|
||||
intervention. Simply pass the --upscale (-U) option on the dream> command line,
|
||||
or indicate the desired scale on the popup in the Web GUI.
|
||||
As of version 1.14, environment.yaml will install the Real-ESRGAN
|
||||
package into the standard install location for python packages, and
|
||||
will put GFPGAN into a subdirectory of "src" in the InvokeAI
|
||||
directory. Upscaling with Real-ESRGAN should "just work" without
|
||||
further intervention. Simply pass the --upscale (-U) option on the
|
||||
invoke> command line, or indicate the desired scale on the popup in
|
||||
the Web GUI.
|
||||
|
||||
For **GFPGAN** to work, there is one additional step needed. You will need to
|
||||
download and copy the GFPGAN
|
||||
[models file](https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.4.pth)
|
||||
into **src/gfpgan/experiments/pretrained_models**. On Mac and Linux systems,
|
||||
here's how you'd do it using **wget**:
|
||||
**GFPGAN** requires a series of downloadable model files to
|
||||
work. These are loaded when you run `scripts/preload_models.py`. If
|
||||
GFPAN is failing with an error, please run the following from the
|
||||
InvokeAI directory:
|
||||
|
||||
```bash
|
||||
wget https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.4.pth -P src/gfpgan/experiments/pretrained_models/
|
||||
```
|
||||
~~~~
|
||||
python scripts/preload_models.py
|
||||
~~~~
|
||||
|
||||
Make sure that you're in the InvokeAI directory when you do this.
|
||||
If you do not run this script in advance, the GFPGAN module will attempt
|
||||
to download the models files the first time you try to perform facial
|
||||
reconstruction.
|
||||
|
||||
Alternatively, if you have GFPGAN installed elsewhere, or if you are using an
|
||||
earlier version of this package which asked you to install GFPGAN in a sibling
|
||||
directory, you may use the `--gfpgan_dir` argument with `dream.py` to set a
|
||||
custom path to your GFPGAN directory. _There are other GFPGAN related boot
|
||||
arguments if you wish to customize further._
|
||||
|
||||
!!! warning "Internet connection needed"
|
||||
|
||||
Users whose GPU machines are isolated from the Internet (e.g.
|
||||
on a University cluster) should be aware that the first time you run dream.py with GFPGAN and
|
||||
Real-ESRGAN turned on, it will try to download model files from the Internet. To rectify this, you
|
||||
may run `python3 scripts/preload_models.py` after you have installed GFPGAN and all its
|
||||
dependencies.
|
||||
Alternatively, if you have GFPGAN installed elsewhere, or if you are
|
||||
using an earlier version of this package which asked you to install
|
||||
GFPGAN in a sibling directory, you may use the `--gfpgan_dir` argument
|
||||
with `invoke.py` to set a custom path to your GFPGAN directory. _There
|
||||
are other GFPGAN related boot arguments if you wish to customize
|
||||
further._
|
||||
|
||||
## Usage
|
||||
|
||||
@ -94,13 +88,13 @@ too.
|
||||
### Example Usage
|
||||
|
||||
```bash
|
||||
dream> superman dancing with a panda bear -U 2 0.6 -G 0.4
|
||||
invoke> superman dancing with a panda bear -U 2 0.6 -G 0.4
|
||||
```
|
||||
|
||||
This also works with img2img:
|
||||
|
||||
```bash
|
||||
dream> a man wearing a pineapple hat -I path/to/your/file.png -U 2 0.5 -G 0.6
|
||||
invoke> a man wearing a pineapple hat -I path/to/your/file.png -U 2 0.5 -G 0.6
|
||||
```
|
||||
|
||||
!!! note
|
||||
@ -124,15 +118,15 @@ actions.
|
||||
This repo also allows you to perform face restoration using
|
||||
[CodeFormer](https://github.com/sczhou/CodeFormer).
|
||||
|
||||
In order to setup CodeFormer to work, you need to download the models like with
|
||||
GFPGAN. You can do this either by running `preload_models.py` or by manually
|
||||
downloading the
|
||||
[model file](https://github.com/sczhou/CodeFormer/releases/download/v0.1.0/codeformer.pth)
|
||||
In order to setup CodeFormer to work, you need to download the models
|
||||
like with GFPGAN. You can do this either by running
|
||||
`preload_models.py` or by manually downloading the [model
|
||||
file](https://github.com/sczhou/CodeFormer/releases/download/v0.1.0/codeformer.pth)
|
||||
and saving it to `ldm/restoration/codeformer/weights` folder.
|
||||
|
||||
You can use `-ft` prompt argument to swap between CodeFormer and the default
|
||||
GFPGAN. The above mentioned `-G` prompt argument will allow you to control the
|
||||
strength of the restoration effect.
|
||||
You can use `-ft` prompt argument to swap between CodeFormer and the
|
||||
default GFPGAN. The above mentioned `-G` prompt argument will allow
|
||||
you to control the strength of the restoration effect.
|
||||
|
||||
### Usage:
|
||||
|
||||
@ -168,7 +162,7 @@ previously-generated file. Just use the syntax `!fix path/to/file.png
|
||||
just run:
|
||||
|
||||
```
|
||||
dream> !fix ./outputs/img-samples/000044.2945021133.png -G 0.8 -U 2
|
||||
invoke> !fix ./outputs/img-samples/000044.2945021133.png -G 0.8 -U 2
|
||||
```
|
||||
|
||||
A new file named `000044.2945021133.fixed.png` will be created in the output
|
||||
@ -178,5 +172,5 @@ unlike the behavior at generate time.
|
||||
### Disabling:
|
||||
|
||||
If, for some reason, you do not wish to load the GFPGAN and/or ESRGAN libraries,
|
||||
you can disable them on the dream.py command line with the `--no_restore` and
|
||||
you can disable them on the invoke.py command line with the `--no_restore` and
|
||||
`--no_upscale` options, respectively.
|
||||
|
@ -6,9 +6,9 @@ title: Prompting Features
|
||||
|
||||
## **Reading Prompts from a File**
|
||||
|
||||
You can automate `dream.py` by providing a text file with the prompts you want to run, one line per
|
||||
You can automate `invoke.py` by providing a text file with the prompts you want to run, one line per
|
||||
prompt. The text file must be composed with a text editor (e.g. Notepad) and not a word processor.
|
||||
Each line should look like what you would type at the dream> prompt:
|
||||
Each line should look like what you would type at the invoke> prompt:
|
||||
|
||||
```bash
|
||||
a beautiful sunny day in the park, children playing -n4 -C10
|
||||
@ -16,39 +16,23 @@ stormy weather on a mountain top, goats grazing -s100
|
||||
innovative packaging for a squid's dinner -S137038382
|
||||
```
|
||||
|
||||
Then pass this file's name to `dream.py` when you invoke it:
|
||||
Then pass this file's name to `invoke.py` when you invoke it:
|
||||
|
||||
```bash
|
||||
(ldm) ~/stable-diffusion$ python3 scripts/dream.py --from_file "path/to/prompts.txt"
|
||||
(ldm) ~/stable-diffusion$ python3 scripts/invoke.py --from_file "path/to/prompts.txt"
|
||||
```
|
||||
|
||||
You may read a series of prompts from standard input by providing a filename of `-`:
|
||||
|
||||
```bash
|
||||
(ldm) ~/stable-diffusion$ echo "a beautiful day" | python3 scripts/dream.py --from_file -
|
||||
(ldm) ~/stable-diffusion$ echo "a beautiful day" | python3 scripts/invoke.py --from_file -
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## **Weighted Prompts**
|
||||
|
||||
You may weight different sections of the prompt to tell the sampler to attach different levels of
|
||||
priority to them, by adding `:(number)` to the end of the section you wish to up- or downweight. For
|
||||
example consider this prompt:
|
||||
|
||||
```bash
|
||||
tabby cat:0.25 white duck:0.75 hybrid
|
||||
```
|
||||
|
||||
This will tell the sampler to invest 25% of its effort on the tabby cat aspect of the image and 75%
|
||||
on the white duck aspect (surprisingly, this example actually works). The prompt weights can use any
|
||||
combination of integers and floating point numbers, and they do not need to add up to 1.
|
||||
|
||||
---
|
||||
|
||||
## **Negative and Unconditioned Prompts**
|
||||
|
||||
Any words between a pair of square brackets will try and be ignored by Stable Diffusion's model during generation of images.
|
||||
Any words between a pair of square brackets will instruct Stable
|
||||
Diffusion to attempt to ban the concept from the generated image.
|
||||
|
||||
```bash
|
||||
this is a test prompt [not really] to make you understand [cool] how this works.
|
||||
@ -88,3 +72,78 @@ Getting close - but there's no sense in having a saddle when our horse doesn't h
|
||||
* You can provide multiple words within the same bracket.
|
||||
* You can provide multiple brackets with multiple words in different places of your prompt. That works just fine.
|
||||
* To improve typical anatomy problems, you can add negative prompts like `[bad anatomy, extra legs, extra arms, extra fingers, poorly drawn hands, poorly drawn feet, disfigured, out of frame, tiling, bad art, deformed, mutated]`.
|
||||
|
||||
---
|
||||
|
||||
## **Prompt Blending**
|
||||
|
||||
You may blend together different sections of the prompt to explore the
|
||||
AI's latent semantic space and generate interesting (and often
|
||||
surprising!) variations. The syntax is:
|
||||
|
||||
```bash
|
||||
blue sphere:0.25 red cube:0.75 hybrid
|
||||
```
|
||||
|
||||
This will tell the sampler to blend 25% of the concept of a blue
|
||||
sphere with 75% of the concept of a red cube. The blend weights can
|
||||
use any combination of integers and floating point numbers, and they
|
||||
do not need to add up to 1. Everything to the left of the `:XX` up to
|
||||
the previous `:XX` is used for merging, so the overall effect is:
|
||||
|
||||
```bash
|
||||
0.25 * "blue sphere" + 0.75 * "white duck" + hybrid
|
||||
```
|
||||
|
||||
Because you are exploring the "mind" of the AI, the AI's way of mixing
|
||||
two concepts may not match yours, leading to surprising effects. To
|
||||
illustrate, here are three images generated using various combinations
|
||||
of blend weights. As usual, unless you fix the seed, the prompts will give you
|
||||
different results each time you run them.
|
||||
|
||||
### "blue sphere, red cube, hybrid"
|
||||
|
||||
This example doesn't use melding at all and represents the default way
|
||||
of mixing concepts.
|
||||
|
||||
<img src="../assets/prompt-blending/blue-sphere-red-cube-hybrid.png" width=256>
|
||||
|
||||
It's interesting to see how the AI expressed the concept of "cube" as
|
||||
the four quadrants of the enclosing frame. If you look closely, there
|
||||
is depth there, so the enclosing frame is actually a cube.
|
||||
|
||||
### "blue sphere:0.25 red cube:0.75 hybrid"
|
||||
|
||||
<img src="../assets/prompt-blending/blue-sphere-0.25-red-cube-0.75-hybrid.png" width=256>
|
||||
|
||||
Now that's interesting. We get neither a blue sphere nor a red cube,
|
||||
but a red sphere embedded in a brick wall, which represents a melding
|
||||
of concepts within the AI's "latent space" of semantic
|
||||
representations. Where is Ludwig Wittgenstein when you need him?
|
||||
|
||||
### "blue sphere:0.75 red cube:0.25 hybrid"
|
||||
|
||||
<img src="../assets/prompt-blending/blue-sphere-0.75-red-cube-0.25-hybrid.png" width=256>
|
||||
|
||||
Definitely more blue-spherey. The cube is gone entirely, but it's
|
||||
really cool abstract art.
|
||||
|
||||
### "blue sphere:0.5 red cube:0.5 hybrid"
|
||||
|
||||
<img src="../assets/prompt-blending/blue-sphere-0.5-red-cube-0.5-hybrid.png" width=256>
|
||||
|
||||
Whoa...! I see blue and red, but no spheres or cubes. Is the word
|
||||
"hybrid" summoning up the concept of some sort of scifi creature?
|
||||
Let's find out.
|
||||
|
||||
### "blue sphere:0.5 red cube:0.5"
|
||||
|
||||
<img src="../assets/prompt-blending/blue-sphere-0.5-red-cube-0.5.png" width=256>
|
||||
|
||||
Indeed, removing the word "hybrid" produces an image that is more like
|
||||
what we'd expect.
|
||||
|
||||
In conclusion, prompt blending is great for exploring creative space,
|
||||
but can be difficult to direct. A forthcoming release of InvokeAI will
|
||||
feature more deterministic prompt weighting.
|
||||
|
||||
|
@ -56,22 +56,22 @@ configs/stable_diffusion/v1-finetune.yaml (currently set to 4000000)
|
||||
## **Run the Model**
|
||||
|
||||
Once the model is trained, specify the trained .pt or .bin file when starting
|
||||
dream using
|
||||
invoke using
|
||||
|
||||
```bash
|
||||
python3 ./scripts/dream.py --embedding_path /path/to/embedding.pt
|
||||
python3 ./scripts/invoke.py --embedding_path /path/to/embedding.pt
|
||||
```
|
||||
|
||||
Then, to utilize your subject at the dream prompt
|
||||
Then, to utilize your subject at the invoke prompt
|
||||
|
||||
```bash
|
||||
dream> "a photo of *"
|
||||
invoke> "a photo of *"
|
||||
```
|
||||
|
||||
This also works with image2image
|
||||
|
||||
```bash
|
||||
dream> "waterfall and rainbow in the style of *" --init_img=./init-images/crude_drawing.png --strength=0.5 -s100 -n4
|
||||
invoke> "waterfall and rainbow in the style of *" --init_img=./init-images/crude_drawing.png --strength=0.5 -s100 -n4
|
||||
```
|
||||
|
||||
For .pt files it's also possible to train multiple tokens (modify the
|
||||
|
@ -34,7 +34,7 @@ First we let SD create a series of images in the usual way, in this case
|
||||
requesting six iterations:
|
||||
|
||||
```bash
|
||||
dream> lucy lawless as xena, warrior princess, character portrait, high resolution -n6
|
||||
invoke> lucy lawless as xena, warrior princess, character portrait, high resolution -n6
|
||||
...
|
||||
Outputs:
|
||||
./outputs/Xena/000001.1579445059.png: "prompt" -s50 -W512 -H512 -C7.5 -Ak_lms -S1579445059
|
||||
@ -57,7 +57,7 @@ differing by a variation amount of 0.2. This number ranges from `0` to `1.0`,
|
||||
with higher numbers being larger amounts of variation.
|
||||
|
||||
```bash
|
||||
dream> "prompt" -n6 -S3357757885 -v0.2
|
||||
invoke> "prompt" -n6 -S3357757885 -v0.2
|
||||
...
|
||||
Outputs:
|
||||
./outputs/Xena/000002.784039624.png: "prompt" -s50 -W512 -H512 -C7.5 -Ak_lms -V 784039624:0.2 -S3357757885
|
||||
@ -89,7 +89,7 @@ We combine the two variations using `-V` (`--with_variations`). Again, we must
|
||||
provide the seed for the originally-chosen image in order for this to work.
|
||||
|
||||
```bash
|
||||
dream> "prompt" -S3357757885 -V3647897225,0.1,1614299449,0.1
|
||||
invoke> "prompt" -S3357757885 -V3647897225,0.1,1614299449,0.1
|
||||
Outputs:
|
||||
./outputs/Xena/000003.1614299449.png: "prompt" -s50 -W512 -H512 -C7.5 -Ak_lms -V 3647897225:0.1,1614299449:0.1 -S3357757885
|
||||
```
|
||||
@ -105,7 +105,7 @@ latter, using both the `-V` (combining) and `-v` (variation strength) options.
|
||||
Note that we use `-n6` to generate 6 variations:
|
||||
|
||||
```bash
|
||||
dream> "prompt" -S3357757885 -V3647897225,0.1,1614299449,0.1 -v0.05 -n6
|
||||
invoke> "prompt" -S3357757885 -V3647897225,0.1,1614299449,0.1 -v0.05 -n6
|
||||
Outputs:
|
||||
./outputs/Xena/000004.3279757577.png: "prompt" -s50 -W512 -H512 -C7.5 -Ak_lms -V 3647897225:0.1,1614299449:0.1,3279757577:0.05 -S3357757885
|
||||
./outputs/Xena/000004.2853129515.png: "prompt" -s50 -W512 -H512 -C7.5 -Ak_lms -V 3647897225:0.1,1614299449:0.1,2853129515:0.05 -S3357757885
|
||||
|
@ -1,24 +1,290 @@
|
||||
---
|
||||
title: InvokeAI Web UI & Server
|
||||
title: InvokeAI Web Server
|
||||
---
|
||||
|
||||
# :material-web: InvokeAI Web Server
|
||||
|
||||
As of version 2.0, this distribution's web server has been updated to include
|
||||
an all-new UI, with optimizations to improve common workflows for image generation.
|
||||
|
||||
## Getting Started & Initialization Commands
|
||||
|
||||
To start the web server, run the `dream.py` script by adding the `--web` parameter.
|
||||
As of version 2.0.0, this distribution comes with a full-featured web
|
||||
server (see screenshot). To use it, run the `invoke.py` script by
|
||||
adding the `--web` option:
|
||||
|
||||
```bash
|
||||
(ldm) ~/stable-diffusion$ python3 scripts/dream.py --web
|
||||
(ldm) ~/InvokeAI$ python3 scripts/invoke.py --web
|
||||
```
|
||||
|
||||
You can then connect to the server by pointing your web browser at
|
||||
http://localhost:9090, or to the network name or IP address of the server.
|
||||
http://localhost:9090. To reach the server from a different machine on
|
||||
your LAN, you may launch the web server with the `--host` argument and
|
||||
either the IP address of the host you are running it on, or the
|
||||
wildcard `0.0.0.0`. For example:
|
||||
|
||||
### Additional Options
|
||||
```bash
|
||||
(ldm) ~/InvokeAI$ python3 scripts/invoke.py --web --host 0.0.0.0
|
||||
```
|
||||
|
||||
# Quick guided walkthrough of the WebGUI's features
|
||||
|
||||
While most of the WebGUI's features are intuitive, here is a guided
|
||||
walkthrough through its various components.
|
||||
|
||||
<img src="../assets/invoke-web-server-1.png" width=640>
|
||||
|
||||
The screenshot above shows the Text to Image tab of the WebGUI. There
|
||||
are three main sections:
|
||||
|
||||
1. A **control panel** on the left, which contains various settings
|
||||
for text to image generation. The most important part is the text
|
||||
field (currently showing `strawberry sushi`) for entering the text
|
||||
prompt, and the camera icon directly underneath that will render the
|
||||
image. We'll call this the *Invoke* button from now on.
|
||||
|
||||
2. The **current image** section in the middle, which shows a large
|
||||
format version of the image you are currently working on. A series of
|
||||
buttons at the top ("image to image", "Use All", "Use Seed", etc) lets
|
||||
you modify the image in various ways.
|
||||
|
||||
3. A **gallery* section on the left that contains a history of the
|
||||
images you have generated. These images are read and written to the
|
||||
directory specified at launch time in `--outdir`.
|
||||
|
||||
In addition to these three elements, there are a series of icons for
|
||||
changing global settings, reporting bugs, and changing the theme on
|
||||
the upper right.
|
||||
|
||||
There are also a series of icons to the left of the control panel (see
|
||||
highlighted area in the screenshot below) which select among a series
|
||||
of tabs for performing different types of operations.
|
||||
|
||||
<img src="../assets/invoke-web-server-2.png" width=512>
|
||||
|
||||
From top to bottom, these are:
|
||||
|
||||
1. Text to Image - generate images from text
|
||||
2. Image to Image - from an uploaded starting image (drawing or photograph) generate a new one, modified by the text prompt
|
||||
3. Inpainting (pending) - Interactively erase portions of a starting image and have the AI fill in the erased region from a text prompt.
|
||||
4. Outpainting (pending) - Interactively add blank space to the borders of a starting image and fill in the background from a text prompt.
|
||||
5. Postprocessing (pending) - Interactively postprocess generated images using a variety of filters.
|
||||
|
||||
The inpainting, outpainting and postprocessing tabs are currently in
|
||||
development. However, limited versions of their features can already
|
||||
be accessed through the Text to Image and Image to Image tabs.
|
||||
|
||||
## Walkthrough
|
||||
|
||||
The following walkthrough will exercise most (but not all) of the
|
||||
WebGUI's feature set.
|
||||
|
||||
### Text to Image
|
||||
|
||||
1. Launch the WebGUI using `python scripts/invoke.py --web` and
|
||||
connect to it with your browser by accessing
|
||||
`http://localhost:9090`. If the browser and server are running on
|
||||
different machines on your LAN, add the option `--host 0.0.0.0` to the
|
||||
launch command line and connect to the machine hosting the web server
|
||||
using its IP address or domain name.
|
||||
|
||||
2. If all goes well, the WebGUI should come up and you'll see a green
|
||||
`connected` message on the upper right.
|
||||
|
||||
#### Basics
|
||||
|
||||
3. Generate an image by typing *strawberry sushi* into the large
|
||||
prompt field on the upper left and then clicking on the Invoke button
|
||||
(the one with the Camera icon). After a short wait, you'll see a large
|
||||
image of sushi in the image panel, and a new thumbnail in the gallery
|
||||
on the right.
|
||||
|
||||
If you need more room on the screen, you can turn the gallery off
|
||||
by clicking on the **x** to the right of "Your Invocations". You can
|
||||
turn it back on later by clicking the image icon that appears in the
|
||||
gallery's place.
|
||||
|
||||
The images are written into the directory indicated by the `--outdir`
|
||||
option provided at script launch time. By default, this is
|
||||
`outputs/img-samples` under the InvokeAI directory.
|
||||
|
||||
4. Generate a bunch of strawberry sushi images by increasing the
|
||||
number of requested images by adjusting the Images counter just below
|
||||
the Camera button. As each is generated, it will be added to the
|
||||
gallery. You can switch the active image by clicking on the gallery
|
||||
thumbnails.
|
||||
|
||||
5. Try playing with different settings, including image width and
|
||||
height, the Sampler, the Steps and the CFG scale.
|
||||
|
||||
Image *Width* and *Height* do what you'd expect. However, be aware that
|
||||
larger images consume more VRAM memory and take longer to generate.
|
||||
|
||||
The *Sampler* controls how the AI selects the image to display. Some
|
||||
samplers are more "creative" than others and will produce a wider
|
||||
range of variations (see next section). Some samplers run faster than
|
||||
others.
|
||||
|
||||
*Steps* controls how many noising/denoising/sampling steps the AI will
|
||||
take. The higher this value, the more refined the image will be, but
|
||||
the longer the image will take to generate. A typical strategy is to
|
||||
generate images with a low number of steps in order to select one to
|
||||
work on further, and then regenerate it using a higher number of
|
||||
steps.
|
||||
|
||||
The *CFG Scale* controls how hard the AI tries to match the generated
|
||||
image to the input prompt. You can go as high or low as you like, but
|
||||
generally values greater than 20 won't improve things much, and values
|
||||
lower than 5 will produce unexpected images. There are complex
|
||||
interactions between *Steps*, *CFG Scale* and the *Sampler*, so
|
||||
experiment to find out what works for you.
|
||||
|
||||
6. To regenerate a previously-generated image, select the image you
|
||||
want and click *Use All*. This loads the text prompt and other
|
||||
original settings into the control panel. If you then press *Invoke*
|
||||
it will regenerate the image exactly. You can also selectively modify
|
||||
the prompt or other settings to tweak the image.
|
||||
|
||||
Alternatively, you may click on *Use Seed* to load just the image's
|
||||
seed, and leave other settings unchanged.
|
||||
|
||||
7. To regenerate a Stable Diffusion image that was generated by
|
||||
another SD package, you need to know its text prompt and its
|
||||
*Seed*. Copy-paste the prompt into the prompt box, unset the
|
||||
*Randomize Seed* control in the control panel, and copy-paste the
|
||||
desired *Seed* into its text field. When you Invoke, you will get
|
||||
something similar to the original image. It will not be exact unless
|
||||
you also set the correct values for the original sampler, CFG,
|
||||
steps and dimensions, but it will (usually) be close.
|
||||
|
||||
#### Variations on a theme
|
||||
|
||||
5. Let's try generating some variations. Select your favorite sushi
|
||||
image from the gallery to load it. Then select "Use All" from the list
|
||||
of buttons above. This will load up all the settings used to generate
|
||||
this image, including its unique seed.
|
||||
|
||||
Go down to the Variations section of the Control Panel and set the
|
||||
button to On. Set Variation Amount to 0.2 to generate a modest
|
||||
number of variations on the image, and also set the Image counter to
|
||||
4. Press the `invoke` button. This will generate a series of related
|
||||
images. To obtain smaller variations, just lower the Variation
|
||||
Amount. You may also experiment with changing the Sampler. Some
|
||||
samplers generate more variability than others. *k_euler_a* is
|
||||
particularly creative, while *ddim* is pretty conservative.
|
||||
|
||||
6. For even more variations, experiment with increasing the setting
|
||||
for *Perlin*. This adds a bit of noise to the image generation
|
||||
process. Note that values of Perlin noise greater than 0.15 produce
|
||||
poor images for several of the samplers.
|
||||
|
||||
#### Facial reconstruction and upscaling
|
||||
|
||||
Stable Diffusion frequently produces mangled faces, particularly when
|
||||
there are multiple figures in the same scene. Stable Diffusion has
|
||||
particular issues with generating reallistic eyes. InvokeAI provides
|
||||
the ability to reconstruct faces using either the GFPGAN or CodeFormer
|
||||
libraries. For more information see [POSTPROCESS](POSTPROCESS.md).
|
||||
|
||||
7. Invoke a prompt that generates a mangled face. A prompt that often
|
||||
gives this is "portrait of a lawyer, 3/4 shot" (this is not intended
|
||||
as a slur against lawyers!) Once you have an image that needs some
|
||||
touching up, load it into the Image panel, and press the button with
|
||||
the face icon (highlighted in the first screenshot below). A dialog
|
||||
box will appear. Leave *Strength* at 0.8 and press *Restore Faces". If
|
||||
all goes well, the eyes and other aspects of the face will be improved
|
||||
(see the second screenshot)
|
||||
|
||||
<img src="../assets/invoke-web-server-3.png">
|
||||
<img src="../assets/invoke-web-server-4.png">
|
||||
|
||||
The facial reconstruction *Strength* field adjusts how aggressively
|
||||
the face library will try to alter the face. It can be as high as 1.0,
|
||||
but be aware that this often softens the face airbrush style, losing
|
||||
some details. The default 0.8 is usually sufficient.
|
||||
|
||||
8. "Upscaling" is the process of increasing the size of an image while
|
||||
retaining the sharpness. InvokeAI uses an external library called
|
||||
"ESRGAN" to do this. To invoke upscaling, simply select an image and
|
||||
press the *HD* button above it. You can select between 2X and 4X
|
||||
upscaling, and adjust the upscaling strength, which has much the same
|
||||
meaning as in facial reconstruction. Try running this on one of your
|
||||
previously-generated images.
|
||||
|
||||
9. Finally, you can run facial reconstruction and/or upscaling
|
||||
automatically after each Invocation. Go to the Advanced Options
|
||||
section of the Control Panel and turn on *Restore Face* and/or
|
||||
*Upscale*.
|
||||
|
||||
### Image to Image
|
||||
|
||||
InvokeAI lets you take an existing image and use it as the basis for a
|
||||
new creation. You can use any sort of image, including a photograph, a
|
||||
scanned sketch, or a digital drawing, as long as it is in PNG or JPEG
|
||||
format.
|
||||
|
||||
For this tutorial, we'll use files named
|
||||
[Lincoln-and-Parrot-512.png](../assets/Lincoln-and-Parrot-512.png),
|
||||
and
|
||||
[Lincoln-and-Parrot-512-transparent.png](../assets/Lincoln-and-Parrot-512-transparent.png).
|
||||
Download these images to your local machine now to continue with the walkthrough.
|
||||
|
||||
10. Click on the *Image to Image* tab icon, which is the second icon
|
||||
from the top on the left-hand side of the screen:
|
||||
|
||||
<img src="../assets/invoke-web-server-5.png">
|
||||
|
||||
This will bring you to a screen similar to the one shown here:
|
||||
|
||||
<img src="../assets/invoke-web-server-6.png" width=640>
|
||||
|
||||
Drag-and-drop the Lincoln-and-Parrot image into the Image panel, or
|
||||
click the blank area to get an upload dialog. The image will load into
|
||||
an area marked *Initial Image*. (The WebGUI will also load the most
|
||||
recently-generated image from the gallery into a section on the left,
|
||||
but this image will be replaced in the next step.)
|
||||
|
||||
11. Go to the prompt box and type *old sea captain with raven on
|
||||
shoulder* and press Invoke. A derived image will appear to the right
|
||||
of the original one:
|
||||
|
||||
<img src="../assets/invoke-web-server-7.png" width=640>
|
||||
|
||||
12. Experiment with the different settings. The most influential one
|
||||
in Image to Image is *Image to Image Strength* located about midway
|
||||
down the control panel. By default it is set to 0.75, but can range
|
||||
from 0.0 to 0.99. The higher the value, the more of the original image
|
||||
the AI will replace. A value of 0 will leave the initial image
|
||||
completely unchanged, while 0.99 will replace it completely. However,
|
||||
the Sampler and CFG Scale also influence the final result. You can
|
||||
also generate variations in the same way as described in Text to
|
||||
Image.
|
||||
|
||||
13. What if we only want to change certain part(s) of the image and
|
||||
leave the rest intact? This is called Inpainting, and a future version
|
||||
of the InvokeAI web server will provide an interactive painting canvas
|
||||
on which you can directly draw the areas you wish to Inpaint into. For
|
||||
now, you can achieve this effect by using an external photoeditor tool
|
||||
to make one or more regions of the image transparent as described in
|
||||
[INPAINTING.md] and uploading that.
|
||||
|
||||
The file
|
||||
[Lincoln-and-Parrot-512-transparent.png](../assets/Lincoln-and-Parrot-512-transparent.png)
|
||||
is a version of the earlier image in which the area around the parrot
|
||||
has been replaced with transparency. Click on the "x" in the upper
|
||||
right of the Initial Image and upload the transparent version. Using
|
||||
the same prompt "old sea captain with raven on shoulder" try Invoking
|
||||
an image. This time, only the parrot will be replaced, leaving the
|
||||
rest of the original image intact:
|
||||
|
||||
<img src="../assets/invoke-web-server-8.png" width=640>
|
||||
|
||||
## Parting remarks
|
||||
|
||||
This concludes the walkthrough, but there are several more features that you
|
||||
can explore. Please check out the [Command Line Interface](CLI.md)
|
||||
documentation for further explanation of the advanced features that
|
||||
were not covered here.
|
||||
|
||||
The WebGUI is only rapid development. Check back regularly for
|
||||
updates!
|
||||
|
||||
# Reference
|
||||
|
||||
## Additional Options
|
||||
`--web_develop` - Starts the web server in development mode.
|
||||
|
||||
`--web_verbose` - Enables verbose logging
|
||||
@ -72,4 +338,3 @@ When an image from the Invocation Gallery is selected, or is generated, the imag
|
||||
## Acknowledgements
|
||||
|
||||
A huge shout-out to the core team working to make this vision a reality, including [psychedelicious](https://github.com/psychedelicious), [Kyle0654](https://github.com/Kyle0654) and [blessedcoolant](https://github.com/blessedcoolant). [hipsterusername](https://github.com/hipsterusername) was the team's unofficial cheerleader and added tooltips/docs.
|
||||
|
||||
|
@ -51,7 +51,7 @@ rm ${PIP_LOG}
|
||||
|
||||
### **QUESTION**
|
||||
|
||||
`dream.py` crashes with the complaint that it can't find `ldm.simplet2i.py`. Or it complains that
|
||||
`invoke.py` crashes with the complaint that it can't find `ldm.simplet2i.py`. Or it complains that
|
||||
function is being passed incorrect parameters.
|
||||
|
||||
### **SOLUTION**
|
||||
@ -63,7 +63,7 @@ Reinstall the stable diffusion modules. Enter the `stable-diffusion` directory a
|
||||
|
||||
### **QUESTION**
|
||||
|
||||
`dream.py` dies, complaining of various missing modules, none of which starts with `ldm``.
|
||||
`invoke.py` dies, complaining of various missing modules, none of which starts with `ldm``.
|
||||
|
||||
### **SOLUTION**
|
||||
|
||||
|
@ -28,7 +28,7 @@ template: main.html
|
||||
[CI checks on dev badge]: https://flat.badgen.net/github/checks/lstein/stable-diffusion/development?label=CI%20status%20on%20dev&cache=900&icon=github
|
||||
[CI checks on dev link]: https://github.com/lstein/stable-diffusion/actions?query=branch%3Adevelopment
|
||||
[CI checks on main badge]: https://flat.badgen.net/github/checks/lstein/stable-diffusion/main?label=CI%20status%20on%20main&cache=900&icon=github
|
||||
[CI checks on main link]: https://github.com/lstein/stable-diffusion/actions/workflows/test-dream-conda.yml
|
||||
[CI checks on main link]: https://github.com/lstein/stable-diffusion/actions/workflows/test-invoke-conda.yml
|
||||
[discord badge]: https://flat.badgen.net/discord/members/htRgbc7e?icon=discord
|
||||
[discord link]: https://discord.com/invite/htRgbc7e
|
||||
[github forks badge]: https://flat.badgen.net/github/forks/lstein/stable-diffusion?icon=github
|
||||
@ -85,21 +85,21 @@ You wil need one of the following:
|
||||
|
||||
!!! note
|
||||
|
||||
If you are have a Nvidia 10xx series card (e.g. the 1080ti), please run the dream script in
|
||||
If you are have a Nvidia 10xx series card (e.g. the 1080ti), please run the invoke script in
|
||||
full-precision mode as shown below.
|
||||
|
||||
Similarly, specify full-precision mode on Apple M1 hardware.
|
||||
|
||||
To run in full-precision mode, start `dream.py` with the `--full_precision` flag:
|
||||
To run in full-precision mode, start `invoke.py` with the `--full_precision` flag:
|
||||
|
||||
```bash
|
||||
(ldm) ~/stable-diffusion$ python scripts/dream.py --full_precision
|
||||
(ldm) ~/stable-diffusion$ python scripts/invoke.py --full_precision
|
||||
```
|
||||
## :octicons-log-16: Latest Changes
|
||||
|
||||
### vNEXT <small>(TODO 2022)</small>
|
||||
|
||||
- Deprecated `--full_precision` / `-F`. Simply omit it and `dream.py` will auto
|
||||
- Deprecated `--full_precision` / `-F`. Simply omit it and `invoke.py` will auto
|
||||
configure. To switch away from auto use the new flag like `--precision=float32`.
|
||||
|
||||
### v1.14 <small>(11 September 2022)</small>
|
||||
@ -124,7 +124,7 @@ You wil need one of the following:
|
||||
[Kevin Gibbons](https://github.com/bakkot)
|
||||
- A new configuration file scheme that allows new models (including upcoming stable-diffusion-v1.5)
|
||||
to be added without altering the code. ([David Wager](https://github.com/maddavid12))
|
||||
- Can specify --grid on dream.py command line as the default.
|
||||
- Can specify --grid on invoke.py command line as the default.
|
||||
- Miscellaneous internal bug and stability fixes.
|
||||
- Works on M1 Apple hardware.
|
||||
- Multiple bug fixes.
|
||||
|
@ -136,7 +136,7 @@ $TAG_STABLE_DIFFUSION
|
||||
|
||||
## Startup
|
||||
|
||||
If you're on a **Linux container** the `dream` script is **automatically
|
||||
If you're on a **Linux container** the `invoke` script is **automatically
|
||||
started** and the output dir set to the Docker volume you created earlier.
|
||||
|
||||
If you're **directly on macOS follow these startup instructions**.
|
||||
@ -148,14 +148,14 @@ half-precision requires autocast and won't work.
|
||||
By default the images are saved in `outputs/img-samples/`.
|
||||
|
||||
```Shell
|
||||
python3 scripts/dream.py --full_precision
|
||||
python3 scripts/invoke.py --full_precision
|
||||
```
|
||||
|
||||
You'll get the script's prompt. You can see available options or quit.
|
||||
|
||||
```Shell
|
||||
dream> -h
|
||||
dream> q
|
||||
invoke> -h
|
||||
invoke> q
|
||||
```
|
||||
|
||||
## Text to Image
|
||||
@ -166,10 +166,10 @@ Then increase steps to 100 or more for good (but slower) results.
|
||||
The prompt can be in quotes or not.
|
||||
|
||||
```Shell
|
||||
dream> The hulk fighting with sheldon cooper -s5 -n1
|
||||
dream> "woman closeup highly detailed" -s 150
|
||||
invoke> The hulk fighting with sheldon cooper -s5 -n1
|
||||
invoke> "woman closeup highly detailed" -s 150
|
||||
# Reuse previous seed and apply face restoration
|
||||
dream> "woman closeup highly detailed" --steps 150 --seed -1 -G 0.75
|
||||
invoke> "woman closeup highly detailed" --steps 150 --seed -1 -G 0.75
|
||||
```
|
||||
|
||||
You'll need to experiment to see if face restoration is making it better or
|
||||
@ -210,28 +210,28 @@ If you're on a Docker container, copy your input image into the Docker volume
|
||||
docker cp /Users/<your-user>/Pictures/sketch-mountains-input.jpg dummy:/data/
|
||||
```
|
||||
|
||||
Try it out generating an image (or more). The `dream` script needs absolute
|
||||
Try it out generating an image (or more). The `invoke` script needs absolute
|
||||
paths to find the image so don't use `~`.
|
||||
|
||||
If you're on your Mac
|
||||
|
||||
```Shell
|
||||
dream> "A fantasy landscape, trending on artstation" -I /Users/<your-user>/Pictures/sketch-mountains-input.jpg --strength 0.75 --steps 100 -n4
|
||||
invoke> "A fantasy landscape, trending on artstation" -I /Users/<your-user>/Pictures/sketch-mountains-input.jpg --strength 0.75 --steps 100 -n4
|
||||
```
|
||||
|
||||
If you're on a Linux container on your Mac
|
||||
|
||||
```Shell
|
||||
dream> "A fantasy landscape, trending on artstation" -I /data/sketch-mountains-input.jpg --strength 0.75 --steps 50 -n1
|
||||
invoke> "A fantasy landscape, trending on artstation" -I /data/sketch-mountains-input.jpg --strength 0.75 --steps 50 -n1
|
||||
```
|
||||
|
||||
## Web Interface
|
||||
|
||||
You can use the `dream` script with a graphical web interface. Start the web
|
||||
You can use the `invoke` script with a graphical web interface. Start the web
|
||||
server with:
|
||||
|
||||
```Shell
|
||||
python3 scripts/dream.py --full_precision --web
|
||||
python3 scripts/invoke.py --full_precision --web
|
||||
```
|
||||
|
||||
If it's running on your Mac point your Mac web browser to http://127.0.0.1:9090
|
||||
|
@ -89,16 +89,16 @@ This will create InvokeAI folder where you will follow the rest of the steps.
|
||||
|
||||
```
|
||||
# for the pre-release weights use the -l or --liaon400m switch
|
||||
(ldm) ~/InvokeAI$ python3 scripts/dream.py -l
|
||||
(ldm) ~/InvokeAI$ python3 scripts/invoke.py -l
|
||||
|
||||
# for the post-release weights do not use the switch
|
||||
(ldm) ~/InvokeAI$ python3 scripts/dream.py
|
||||
(ldm) ~/InvokeAI$ python3 scripts/invoke.py
|
||||
|
||||
# for additional configuration switches and arguments, use -h or --help
|
||||
(ldm) ~/InvokeAI$ python3 scripts/dream.py -h
|
||||
(ldm) ~/InvokeAI$ python3 scripts/invoke.py -h
|
||||
```
|
||||
|
||||
9. Subsequently, to relaunch the script, be sure to run "conda activate ldm" (step 5, second command), enter the `InvokeAI` directory, and then launch the dream script (step 8). If you forget to activate the ldm environment, the script will fail with multiple `ModuleNotFound` errors.
|
||||
9. Subsequently, to relaunch the script, be sure to run "conda activate ldm" (step 5, second command), enter the `InvokeAI` directory, and then launch the invoke script (step 8). If you forget to activate the ldm environment, the script will fail with multiple `ModuleNotFound` errors.
|
||||
|
||||
## Updating to newer versions of the script
|
||||
|
||||
|
@ -2,145 +2,113 @@
|
||||
title: macOS
|
||||
---
|
||||
|
||||
# :fontawesome-brands-apple: macOS
|
||||
Invoke AI runs quite well on M1 Macs and we have a number of M1 users
|
||||
in the community.
|
||||
|
||||
While the repo does run on Intel Macs, we only have a couple
|
||||
reports. If you have an Intel Mac and run into issues, please create
|
||||
an issue on Github and we will do our best to help.
|
||||
|
||||
## Requirements
|
||||
|
||||
- macOS 12.3 Monterey or later
|
||||
- Python
|
||||
- Patience
|
||||
- Apple Silicon or Intel Mac
|
||||
- About 10GB of storage (and 10GB of data if your internet connection has data caps)
|
||||
- Any M1 Macs or an Intel Macs with 4GB+ of VRAM (ideally more)
|
||||
|
||||
Things have moved really fast and so these instructions change often which makes
|
||||
them outdated pretty fast. One of the problems is that there are so many
|
||||
different ways to run this.
|
||||
## Installation
|
||||
|
||||
We are trying to build a testing setup so that when we make changes it doesn't
|
||||
always break.
|
||||
First you need to download a large checkpoint file.
|
||||
|
||||
## How to
|
||||
1. Sign up at https://huggingface.co
|
||||
2. Go to the [Stable diffusion diffusion model page](https://huggingface.co/CompVis/stable-diffusion-v-1-4-original)
|
||||
3. Accept the terms and click Access Repository
|
||||
4. Download [sd-v1-4.ckpt (4.27 GB)](https://huggingface.co/CompVis/stable-diffusion-v-1-4-original/blob/main/sd-v1-4.ckpt) and note where you have saved it (probably the Downloads folder). You may want to move it somewhere else for longer term storage - SD needs this file to run.
|
||||
|
||||
(this hasn't been 100% tested yet)
|
||||
While that is downloading, open Terminal and run the following
|
||||
commands one at a time, reading the comments and taking care to run
|
||||
the appropriate command for your Mac's architecture (Intel or M1).
|
||||
|
||||
First get the weights checkpoint download started since it's big and will take
|
||||
some time:
|
||||
Do not just copy and paste the whole thing into your terminal!
|
||||
|
||||
1. Sign up at [huggingface.co](https://huggingface.co)
|
||||
2. Go to the
|
||||
[Stable diffusion diffusion model page](https://huggingface.co/CompVis/stable-diffusion-v-1-4-original)
|
||||
3. Accept the terms and click Access Repository:
|
||||
4. Download
|
||||
[sd-v1-4.ckpt (4.27 GB)](https://huggingface.co/CompVis/stable-diffusion-v-1-4-original/blob/main/sd-v1-4.ckpt)
|
||||
and note where you have saved it (probably the Downloads folder)
|
||||
```bash
|
||||
# Install brew (and Xcode command line tools):
|
||||
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||
|
||||
While that is downloading, open a Terminal and run the following commands:
|
||||
# Now there are two options to get the Python (miniconda) environment up and running:
|
||||
# 1. Alongside pyenv
|
||||
# 2. Standalone
|
||||
#
|
||||
# If you don't know what we are talking about, choose 2.
|
||||
#
|
||||
# If you are familiar with python environments, you'll know there are other options
|
||||
# for setting up the environment - you are on your own if you go one of those routes.
|
||||
##### BEGIN TWO DIFFERENT OPTIONS #####
|
||||
|
||||
!!! todo "Homebrew"
|
||||
### BEGIN OPTION 1: Installing alongside pyenv ###
|
||||
brew install pyenv-virtualenv # you might have this from before, no problem
|
||||
pyenv install anaconda3-2022.05
|
||||
pyenv virtualenv anaconda3-2022.05
|
||||
eval "$(pyenv init -)"
|
||||
pyenv activate anaconda3-2022.05
|
||||
### END OPTION 1 ###
|
||||
|
||||
=== "no brew installation yet"
|
||||
|
||||
```bash title="install brew (and Xcode command line tools)"
|
||||
/bin/bash -c \
|
||||
"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||
```
|
||||
### BEGIN OPTION 2: Installing standalone ###
|
||||
# Install cmake, protobuf, and rust:
|
||||
brew install cmake protobuf rust
|
||||
|
||||
=== "brew is already installed"
|
||||
|
||||
Only if you installed protobuf in a previous version of this tutorial, otherwise skip
|
||||
# BEGIN ARCHITECTURE-DEPENDENT STEP #
|
||||
# For M1: install miniconda (M1 arm64 version):
|
||||
curl https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-arm64.sh -o Miniconda3-latest-MacOSX-arm64.sh
|
||||
/bin/bash Miniconda3-latest-MacOSX-arm64.sh
|
||||
|
||||
`#!bash brew uninstall protobuf`
|
||||
# For Intel: install miniconda (Intel x86-64 version):
|
||||
curl https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-x86_64.sh -o Miniconda3-latest-MacOSX-x86_64.sh
|
||||
/bin/bash Miniconda3-latest-MacOSX-x86_64.sh
|
||||
# END ARCHITECTURE-DEPENDENT STEP #
|
||||
|
||||
!!! todo "Conda Installation"
|
||||
### END OPTION 2 ###
|
||||
|
||||
Now there are two different ways to set up the Python (miniconda) environment:
|
||||
1. Standalone
|
||||
2. with pyenv
|
||||
If you don't know what we are talking about, choose Standalone
|
||||
##### END TWO DIFFERENT OPTIONS #####
|
||||
|
||||
=== "Standalone"
|
||||
|
||||
```bash
|
||||
# install cmake and rust:
|
||||
brew install cmake rust
|
||||
```
|
||||
|
||||
=== "M1 arm64"
|
||||
|
||||
```bash title="Install miniconda for M1 arm64"
|
||||
curl https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-arm64.sh \
|
||||
-o Miniconda3-latest-MacOSX-arm64.sh
|
||||
/bin/bash Miniconda3-latest-MacOSX-arm64.sh
|
||||
```
|
||||
|
||||
=== "Intel x86_64"
|
||||
|
||||
```bash title="Install miniconda for Intel"
|
||||
curl https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-x86_64.sh \
|
||||
-o Miniconda3-latest-MacOSX-x86_64.sh
|
||||
/bin/bash Miniconda3-latest-MacOSX-x86_64.sh
|
||||
```
|
||||
|
||||
=== "with pyenv"
|
||||
|
||||
```{.bash .annotate}
|
||||
brew install rust pyenv-virtualenv # (1)!
|
||||
pyenv install anaconda3-2022.05
|
||||
pyenv virtualenv anaconda3-2022.05
|
||||
eval "$(pyenv init -)"
|
||||
pyenv activate anaconda3-2022.05
|
||||
```
|
||||
|
||||
1. You might already have this installed, if that is the case just continue.
|
||||
|
||||
```{.bash .annotate title="local repo setup"}
|
||||
# clone the repo
|
||||
# Clone the Invoke AI repo
|
||||
git clone https://github.com/invoke-ai/InvokeAI.git
|
||||
|
||||
cd InvokeAI
|
||||
<<<<<<< HEAD
|
||||
|
||||
# wait until the checkpoint file has downloaded, then proceed
|
||||
### WAIT FOR THE CHECKPOINT FILE TO DOWNLOAD, THEN PROCEED ###
|
||||
# We will leave the big checkpoint wherever you stashed it for long-term storage,
|
||||
# and make a link to it from the repo's folder. This allows you to use it for
|
||||
# other repos, and if you need to delete Invoke AI, you won't have to download it again.
|
||||
|
||||
# create symlink to checkpoint
|
||||
# Make the directory in the repo for the symlink
|
||||
mkdir -p models/ldm/stable-diffusion-v1/
|
||||
|
||||
PATH_TO_CKPT="$HOME/Downloads" # (1)!
|
||||
# This is the folder where you put the checkpoint file `sd-v1-4.ckpt`
|
||||
PATH_TO_CKPT="$HOME/Downloads"
|
||||
|
||||
ln -s "$PATH_TO_CKPT/sd-v1-4.ckpt" \
|
||||
models/ldm/stable-diffusion-v1/model.ckpt
|
||||
```
|
||||
# Create a link to the checkpoint
|
||||
ln -s "$PATH_TO_CKPT/sd-v1-4.ckpt" models/ldm/stable-diffusion-v1/model.ckpt
|
||||
|
||||
1. or wherever you saved sd-v1-4.ckpt
|
||||
# BEGIN ARCHITECTURE-DEPENDENT STEP #
|
||||
# For M1: Create the environment & install packages
|
||||
PIP_EXISTS_ACTION=w CONDA_SUBDIR=osx-arm64 conda env create -f environment-mac.yaml
|
||||
|
||||
!!! todo "create Conda Environment"
|
||||
# For Intel: Create the environment & install packages
|
||||
PIP_EXISTS_ACTION=w CONDA_SUBDIR=osx-64 conda env create -f environment-mac.yaml
|
||||
# END ARCHITECTURE-DEPENDENT STEP #
|
||||
|
||||
=== "M1 arm64"
|
||||
# Activate the environment (you need to do this every time you want to run SD)
|
||||
conda activate ldm
|
||||
|
||||
```bash
|
||||
PIP_EXISTS_ACTION=w CONDA_SUBDIR=osx-arm64 \
|
||||
conda env create \
|
||||
-f environment-mac.yml \
|
||||
&& conda activate ldm
|
||||
```
|
||||
|
||||
|
||||
=== "Intel x86_64"
|
||||
|
||||
```bash
|
||||
PIP_EXISTS_ACTION=w CONDA_SUBDIR=osx-64 \
|
||||
conda env create \
|
||||
-f environment-mac.yml \
|
||||
&& conda activate ldm
|
||||
```
|
||||
|
||||
```{.bash .annotate title="preload models and run script"}
|
||||
# only need to do this once
|
||||
# This will download some bits and pieces and make take a while
|
||||
python scripts/preload_models.py
|
||||
|
||||
# now you can run SD in CLI mode
|
||||
python scripts/dream.py --full_precision # (1)!
|
||||
|
||||
# Run SD!
|
||||
python scripts/dream.py
|
||||
```
|
||||
# or run the web interface!
|
||||
python scripts/dream.py --web
|
||||
python scripts/invoke.py --web
|
||||
|
||||
# The original scripts should work as well.
|
||||
python scripts/orig_scripts/txt2img.py \
|
||||
@ -155,7 +123,7 @@ it isn't required but wont hurt.
|
||||
|
||||
## Common problems
|
||||
|
||||
After you followed all the instructions and try to run dream.py, you might
|
||||
After you followed all the instructions and try to run invoke.py, you might
|
||||
get several errors. Here's the errors I've seen and found solutions for.
|
||||
|
||||
### Is it slow?
|
||||
@ -172,13 +140,13 @@ python ./scripts/orig_scripts/txt2img.py \
|
||||
|
||||
### Doesn't work anymore?
|
||||
|
||||
PyTorch nightly includes support for MPS. Because of this, this setup is
|
||||
inherently unstable. One morning I woke up and it no longer worked no matter
|
||||
what I did until I switched to miniforge. However, I have another Mac that works
|
||||
just fine with Anaconda. If you can't get it to work, please search a little
|
||||
first because many of the errors will get posted and solved. If you can't find a
|
||||
solution please
|
||||
[create an issue](https://github.com/invoke-ai/InvokeAI/issues).
|
||||
PyTorch nightly includes support for MPS. Because of this, this setup
|
||||
is inherently unstable. One morning I woke up and it no longer worked
|
||||
no matter what I did until I switched to miniforge. However, I have
|
||||
another Mac that works just fine with Anaconda. If you can't get it to
|
||||
work, please search a little first because many of the errors will get
|
||||
posted and solved. If you can't find a solution please [create an
|
||||
issue](https://github.com/invoke-ai/InvokeAI/issues).
|
||||
|
||||
One debugging step is to update to the latest version of PyTorch nightly.
|
||||
|
||||
@ -220,9 +188,9 @@ There are several causes of these errors:
|
||||
"(ldm)" then you activated it. If it begins with "(base)" or something else
|
||||
you haven't.
|
||||
|
||||
2. You might've run `./scripts/preload_models.py` or `./scripts/dream.py`
|
||||
2. You might've run `./scripts/preload_models.py` or `./scripts/invoke.py`
|
||||
instead of `python ./scripts/preload_models.py` or
|
||||
`python ./scripts/dream.py`. The cause of this error is long so it's below.
|
||||
`python ./scripts/invoke.py`. The cause of this error is long so it's below.
|
||||
|
||||
<!-- I could not find out where the error is, otherwise would have marked it as a footnote -->
|
||||
|
||||
@ -378,8 +346,8 @@ python scripts/preload_models.py
|
||||
WARNING: this will be slower than running natively on MPS.
|
||||
```
|
||||
|
||||
This fork already includes a fix for this in
|
||||
[environment-mac.yml](https://github.com/invoke-ai/InvokeAI/blob/main/environment-mac.yml).
|
||||
The InvokeAI version includes this fix in
|
||||
[environment-mac.yaml](https://github.com/invoke-ai/InvokeAI/blob/main/environment-mac.yaml).
|
||||
|
||||
### "Could not build wheels for tokenizers"
|
||||
|
||||
@ -463,13 +431,10 @@ C.
|
||||
|
||||
You don't have a virus. It's part of the project. Here's
|
||||
[Rick](https://github.com/invoke-ai/InvokeAI/blob/main/assets/rick.jpeg)
|
||||
and here's
|
||||
[the code](https://github.com/invoke-ai/InvokeAI/blob/69ae4b35e0a0f6ee1af8bb9a5d0016ccb27e36dc/scripts/txt2img.py#L79)
|
||||
that swaps him in. It's a NSFW filter, which IMO, doesn't work very good (and we
|
||||
call this "computer vision", sheesh).
|
||||
|
||||
Actually, this could be happening because there's not enough RAM. You could try
|
||||
the `model.half()` suggestion or specify smaller output images.
|
||||
and here's [the
|
||||
code](https://github.com/invoke-ai/InvokeAI/blob/69ae4b35e0a0f6ee1af8bb9a5d0016ccb27e36dc/scripts/txt2img.py#L79)
|
||||
that swaps him in. It's a NSFW filter, which IMO, doesn't work very
|
||||
good (and we call this "computer vision", sheesh).
|
||||
|
||||
---
|
||||
|
||||
@ -492,11 +457,9 @@ return torch.layer_norm(input, normalized_shape, weight, bias, eps, torch.backen
|
||||
RuntimeError: view size is not compatible with input tensor's size and stride (at least one dimension spans across two contiguous subspaces). Use .reshape(...) instead.
|
||||
```
|
||||
|
||||
Update to the latest version of invoke-ai/InvokeAI. We were patching
|
||||
pytorch but we found a file in stable-diffusion that we could change instead.
|
||||
This is a 32-bit vs 16-bit problem.
|
||||
|
||||
---
|
||||
Update to the latest version of invoke-ai/InvokeAI. We were
|
||||
patching pytorch but we found a file in stable-diffusion that we could
|
||||
change instead. This is a 32-bit vs 16-bit problem.
|
||||
|
||||
### The processor must support the Intel bla bla bla
|
||||
|
||||
@ -519,7 +482,7 @@ use ARM packages, and use `nomkl` as described above.
|
||||
May appear when just starting to generate, e.g.:
|
||||
|
||||
```bash
|
||||
dream> clouds
|
||||
invoke> clouds
|
||||
Generating: 0%| | 0/1 [00:00<?, ?it/s]/Users/[...]/dev/stable-diffusion/ldm/modules/embedding_manager.py:152: UserWarning: The operator 'aten::nonzero' is not currently supported on the MPS backend and will fall back to run on the CPU. This may have performance implications. (Triggered internally at /Users/runner/work/_temp/anaconda/conda-bld/pytorch_1662016319283/work/aten/src/ATen/mps/MPSFallback.mm:11.)
|
||||
placeholder_idx = torch.where(
|
||||
loc("mps_add"("(mpsFileLoc): /AppleInternal/Library/BuildRoots/20d6c351-ee94-11ec-bcaf-7247572f23b4/Library/Caches/com.apple.xbs/Sources/MetalPerformanceShadersGraph/mpsgraph/MetalPerformanceShadersGraph/Core/Files/MPSGraphUtilities.mm":219:0)): error: input types 'tensor<2x1280xf32>' and 'tensor<*xf16>' are not broadcast compatible
|
||||
|
@ -101,13 +101,13 @@ you may instead create a shortcut to it from within `models\ldm\stable-diffusion
|
||||
|
||||
```bash
|
||||
# for the pre-release weights
|
||||
python scripts\dream.py -l
|
||||
python scripts\invoke.py -l
|
||||
|
||||
# for the post-release weights
|
||||
python scripts\dream.py
|
||||
python scripts\invoke.py
|
||||
```
|
||||
|
||||
10. Subsequently, to relaunch the script, first activate the Anaconda command window (step 3),enter the InvokeAI directory (step 5, `cd \path\to\InvokeAI`), run `conda activate ldm` (step 6b), and then launch the dream script (step 9).
|
||||
10. Subsequently, to relaunch the script, first activate the Anaconda command window (step 3),enter the InvokeAI directory (step 5, `cd \path\to\InvokeAI`), run `conda activate ldm` (step 6b), and then launch the invoke script (step 9).
|
||||
|
||||
**Note:** Tildebyte has written an alternative
|
||||
["Easy peasy Windows install"](https://github.com/invoke-ai/InvokeAI/wiki/Easy-peasy-Windows-install)
|
||||
|
@ -3,12 +3,12 @@ channels:
|
||||
- pytorch
|
||||
- conda-forge
|
||||
dependencies:
|
||||
- python==3.10.5
|
||||
- python==3.9.13
|
||||
- pip==22.2.2
|
||||
|
||||
|
||||
# pytorch left unpinned
|
||||
- pytorch
|
||||
- torchvision
|
||||
- pytorch==1.12.1
|
||||
- torchvision==0.13.1
|
||||
|
||||
# I suggest to keep the other deps sorted for convenience.
|
||||
# To determine what the latest versions should be, run:
|
||||
@ -27,13 +27,12 @@ dependencies:
|
||||
- imgaug==0.4.0
|
||||
- kornia==0.6.7
|
||||
- mpmath==1.2.1
|
||||
- nomkl
|
||||
- nomkl=1.0
|
||||
- numpy==1.23.2
|
||||
- omegaconf==2.1.1
|
||||
- openh264==2.3.0
|
||||
- onnx==1.12.0
|
||||
- onnxruntime==1.12.1
|
||||
- protobuf==3.19.4
|
||||
- pudb==2022.1
|
||||
- pytorch-lightning==1.7.5
|
||||
- scipy==1.9.1
|
||||
@ -42,22 +41,22 @@ dependencies:
|
||||
- tensorboard==2.10.0
|
||||
- torchmetrics==0.9.3
|
||||
- pip:
|
||||
- flask==2.1.3
|
||||
- flask_socketio==5.3.0
|
||||
- flask_cors==3.0.10
|
||||
- dependency_injector==4.40.0
|
||||
- eventlet
|
||||
- opencv-python==4.6.0
|
||||
- protobuf==3.20.1
|
||||
- realesrgan==0.2.5.0
|
||||
- send2trash==1.8.0
|
||||
- test-tube==0.7.5
|
||||
- transformers==4.21.2
|
||||
- torch-fidelity==0.3.0
|
||||
- -e git+https://github.com/CompVis/taming-transformers.git@master#egg=taming-transformers
|
||||
- -e git+https://github.com/openai/CLIP.git@main#egg=clip
|
||||
- -e git+https://github.com/Birch-san/k-diffusion.git@mps#egg=k_diffusion
|
||||
- -e git+https://github.com/lstein/GFPGAN@fix-dark-cast-images#egg=gfpgan
|
||||
- -e .
|
||||
- flask==2.1.3
|
||||
- flask_socketio==5.3.0
|
||||
- flask_cors==3.0.10
|
||||
- dependency_injector==4.40.0
|
||||
- eventlet==0.33.1
|
||||
- opencv-python==4.6.0
|
||||
- protobuf==3.19.5
|
||||
- realesrgan==0.2.5.0
|
||||
- send2trash==1.8.0
|
||||
- test-tube==0.7.5
|
||||
- transformers==4.21.2
|
||||
- torch-fidelity==0.3.0
|
||||
- -e git+https://github.com/CompVis/taming-transformers.git@master#egg=taming-transformers
|
||||
- -e git+https://github.com/openai/CLIP.git@main#egg=clip
|
||||
- -e git+https://github.com/Birch-san/k-diffusion.git@mps#egg=k_diffusion
|
||||
- -e git+https://github.com/TencentARC/GFPGAN.git#egg=gfpgan
|
||||
- -e .
|
||||
variables:
|
||||
PYTORCH_ENABLE_MPS_FALLBACK: 1
|
||||
|
@ -36,5 +36,5 @@ dependencies:
|
||||
- -e git+https://github.com/openai/CLIP.git@main#egg=clip
|
||||
- -e git+https://github.com/CompVis/taming-transformers.git@master#egg=taming-transformers
|
||||
- -e git+https://github.com/Birch-san/k-diffusion.git@mps#egg=k_diffusion
|
||||
- -e git+https://github.com/lstein/GFPGAN@fix-dark-cast-images#egg=gfpgan
|
||||
- -e git+https://github.com/TencentARC/GFPGAN.git#egg=gfpgan
|
||||
- -e .
|
||||
|
1
frontend/dist/assets/index.4ceb640a.css
vendored
Normal file
483
frontend/dist/assets/index.6cdae835.js
vendored
Normal file
6
frontend/dist/index.html
vendored
@ -6,8 +6,8 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>InvokeAI - A Stable Diffusion Toolkit</title>
|
||||
<link rel="shortcut icon" type="icon" href="/assets/favicon.0d253ced.ico" />
|
||||
<script type="module" crossorigin src="/assets/index.27eefde8.js"></script>
|
||||
<link rel="stylesheet" href="/assets/index.c04b2fd8.css">
|
||||
<script type="module" crossorigin src="/assets/index.6cdae835.js"></script>
|
||||
<link rel="stylesheet" href="/assets/index.4ceb640a.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
@ -15,4 +15,4 @@
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
@ -71,7 +71,7 @@
|
||||
.next-prev-button-trigger-area {
|
||||
width: 7rem;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
width: 15%;
|
||||
display: grid;
|
||||
align-items: center;
|
||||
pointer-events: auto;
|
||||
|
@ -16,8 +16,12 @@ const SeedOptions = () => {
|
||||
<Seed />
|
||||
<ShuffleSeed />
|
||||
</Flex>
|
||||
<Threshold />
|
||||
<Perlin />
|
||||
<Flex gap={2}>
|
||||
<Threshold />
|
||||
</Flex>
|
||||
<Flex gap={2}>
|
||||
<Perlin />
|
||||
</Flex>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
@ -252,7 +252,9 @@ export const optionsSlice = createSlice({
|
||||
if (steps) state.steps = steps;
|
||||
if (cfg_scale) state.cfgScale = cfg_scale;
|
||||
if (threshold) state.threshold = threshold;
|
||||
if (typeof threshold === 'undefined') state.threshold = 0;
|
||||
if (perlin) state.perlin = perlin;
|
||||
if (typeof perlin === 'undefined') state.perlin = 0;
|
||||
if (typeof seamless === 'boolean') state.seamless = seamless;
|
||||
if (width) state.width = width;
|
||||
if (height) state.height = height;
|
||||
|
@ -21,7 +21,7 @@
|
||||
|
||||
.site-header-right-side {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(6, max-content);
|
||||
grid-template-columns: repeat(7, max-content);
|
||||
align-items: center;
|
||||
column-gap: 0.5rem;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { IconButton, Link, Tooltip, useColorMode } from '@chakra-ui/react';
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
|
||||
import { FaSun, FaMoon, FaGithub } from 'react-icons/fa';
|
||||
import { FaSun, FaMoon, FaGithub, FaDiscord } from 'react-icons/fa';
|
||||
import { MdHelp, MdKeyboard, MdSettings } from 'react-icons/md';
|
||||
|
||||
import InvokeAILogo from '../../assets/images/logo.png';
|
||||
@ -70,7 +70,7 @@ const SiteHeader = () => {
|
||||
icon={
|
||||
<Link
|
||||
isExternal
|
||||
href="http://github.com/lstein/stable-diffusion/issues"
|
||||
href="http://github.com/invoke-ai/InvokeAI/issues"
|
||||
>
|
||||
<MdHelp />
|
||||
</Link>
|
||||
@ -85,13 +85,27 @@ const SiteHeader = () => {
|
||||
fontSize={20}
|
||||
size={'sm'}
|
||||
icon={
|
||||
<Link isExternal href="http://github.com/lstein/stable-diffusion">
|
||||
<Link isExternal href="http://github.com/invoke-ai/InvokeAI">
|
||||
<FaGithub />
|
||||
</Link>
|
||||
}
|
||||
/>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip hasArrow label="Discord" placement={'bottom'}>
|
||||
<IconButton
|
||||
aria-label="Link to Discord Server"
|
||||
variant="link"
|
||||
fontSize={20}
|
||||
size={'sm'}
|
||||
icon={
|
||||
<Link isExternal href="https://discord.gg/ZmtBAhwWhy">
|
||||
<FaDiscord />
|
||||
</Link>
|
||||
}
|
||||
/>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip hasArrow label="Theme" placement={'bottom'}>
|
||||
<IconButton
|
||||
aria-label="Toggle Dark Mode"
|
||||
|
@ -1,4 +0,0 @@
|
||||
'''
|
||||
Initialization file for the ldm.dream.generator package
|
||||
'''
|
||||
from .base import Generator
|
@ -1,4 +0,0 @@
|
||||
'''
|
||||
Initialization file for the ldm.dream.restoration package
|
||||
'''
|
||||
from .base import Restoration
|
@ -19,7 +19,7 @@ import cv2
|
||||
import skimage
|
||||
|
||||
from omegaconf import OmegaConf
|
||||
from ldm.dream.generator.base import downsampling
|
||||
from ldm.invoke.generator.base import downsampling
|
||||
from PIL import Image, ImageOps
|
||||
from torch import nn
|
||||
from pytorch_lightning import seed_everything, logging
|
||||
@ -28,33 +28,11 @@ from ldm.util import instantiate_from_config
|
||||
from ldm.models.diffusion.ddim import DDIMSampler
|
||||
from ldm.models.diffusion.plms import PLMSSampler
|
||||
from ldm.models.diffusion.ksampler import KSampler
|
||||
from ldm.dream.pngwriter import PngWriter
|
||||
from ldm.dream.args import metadata_from_png
|
||||
from ldm.dream.image_util import InitImageResizer
|
||||
from ldm.dream.devices import choose_torch_device, choose_precision
|
||||
from ldm.dream.conditioning import get_uc_and_c
|
||||
|
||||
|
||||
|
||||
def fix_func(orig):
|
||||
if hasattr(torch.backends, 'mps') and torch.backends.mps.is_available():
|
||||
def new_func(*args, **kw):
|
||||
device = kw.get("device", "mps")
|
||||
kw["device"]="cpu"
|
||||
return orig(*args, **kw).to(device)
|
||||
return new_func
|
||||
return orig
|
||||
|
||||
torch.rand = fix_func(torch.rand)
|
||||
torch.rand_like = fix_func(torch.rand_like)
|
||||
torch.randn = fix_func(torch.randn)
|
||||
torch.randn_like = fix_func(torch.randn_like)
|
||||
torch.randint = fix_func(torch.randint)
|
||||
torch.randint_like = fix_func(torch.randint_like)
|
||||
torch.bernoulli = fix_func(torch.bernoulli)
|
||||
torch.multinomial = fix_func(torch.multinomial)
|
||||
|
||||
|
||||
from ldm.invoke.pngwriter import PngWriter
|
||||
from ldm.invoke.args import metadata_from_png
|
||||
from ldm.invoke.image_util import InitImageResizer
|
||||
from ldm.invoke.devices import choose_torch_device, choose_precision
|
||||
from ldm.invoke.conditioning import get_uc_and_c
|
||||
|
||||
"""Simplified text to image API for stable diffusion/latent diffusion
|
||||
|
||||
@ -142,7 +120,8 @@ class Generate:
|
||||
config = None,
|
||||
gfpgan=None,
|
||||
codeformer=None,
|
||||
esrgan=None
|
||||
esrgan=None,
|
||||
free_gpu_mem=False,
|
||||
):
|
||||
models = OmegaConf.load(conf)
|
||||
mconfig = models[model]
|
||||
@ -169,6 +148,7 @@ class Generate:
|
||||
self.gfpgan = gfpgan
|
||||
self.codeformer = codeformer
|
||||
self.esrgan = esrgan
|
||||
self.free_gpu_mem = free_gpu_mem
|
||||
|
||||
# Note that in previous versions, there was an option to pass the
|
||||
# device to Generate(). However the device was then ignored, so
|
||||
@ -295,9 +275,9 @@ class Generate:
|
||||
def process_image(image,seed):
|
||||
image.save(f{'images/seed.png'})
|
||||
|
||||
The callback used by the prompt2png() can be found in ldm/dream_util.py. It contains code
|
||||
to create the requested output directory, select a unique informative name for each image, and
|
||||
write the prompt into the PNG metadata.
|
||||
The code used to save images to a directory can be found in ldm/invoke/pngwriter.py.
|
||||
It contains code to create the requested output directory, select a unique informative
|
||||
name for each image, and write the prompt into the PNG metadata.
|
||||
"""
|
||||
# TODO: convert this into a getattr() loop
|
||||
steps = steps or self.steps
|
||||
@ -385,7 +365,8 @@ class Generate:
|
||||
generator = self._make_txt2img()
|
||||
|
||||
generator.set_variation(
|
||||
self.seed, variation_amount, with_variations)
|
||||
self.seed, variation_amount, with_variations
|
||||
)
|
||||
results = generator.generate(
|
||||
prompt,
|
||||
iterations=iterations,
|
||||
@ -521,7 +502,7 @@ class Generate:
|
||||
)
|
||||
|
||||
elif tool == 'outcrop':
|
||||
from ldm.dream.restoration.outcrop import Outcrop
|
||||
from ldm.invoke.restoration.outcrop import Outcrop
|
||||
extend_instructions = {}
|
||||
for direction,pixels in _pairwise(opt.outcrop):
|
||||
extend_instructions[direction]=int(pixels)
|
||||
@ -558,7 +539,7 @@ class Generate:
|
||||
image_callback = callback,
|
||||
)
|
||||
elif tool == 'outpaint':
|
||||
from ldm.dream.restoration.outpaint import Outpaint
|
||||
from ldm.invoke.restoration.outpaint import Outpaint
|
||||
restorer = Outpaint(image,self)
|
||||
return restorer.process(
|
||||
opt,
|
||||
@ -594,18 +575,14 @@ class Generate:
|
||||
height,
|
||||
)
|
||||
|
||||
if image.width < self.width and image.height < self.height:
|
||||
print(f'>> WARNING: img2img and inpainting may produce unexpected results with initial images smaller than {self.width}x{self.height} in both dimensions')
|
||||
|
||||
# if image has a transparent area and no mask was provided, then try to generate mask
|
||||
if self._has_transparency(image) and not mask:
|
||||
print(
|
||||
'>> Initial image has transparent areas. Will inpaint in these regions.')
|
||||
if self._check_for_erasure(image):
|
||||
print(
|
||||
'>> WARNING: Colors underneath the transparent region seem to have been erased.\n',
|
||||
'>> Inpainting will be suboptimal. Please preserve the colors when making\n',
|
||||
'>> a transparency mask, or provide mask explicitly using --init_mask (-M).'
|
||||
)
|
||||
if self._has_transparency(image):
|
||||
self._transparency_check_and_warning(image, mask)
|
||||
# this returns a torch tensor
|
||||
init_mask = self._create_init_mask(image,width,height,fit=fit)
|
||||
init_mask = self._create_init_mask(image, width, height, fit=fit)
|
||||
|
||||
if (image.width * image.height) > (self.width * self.height):
|
||||
print(">> This input is larger than your defaults. If you run out of memory, please use a smaller image.")
|
||||
@ -621,39 +598,39 @@ class Generate:
|
||||
|
||||
def _make_base(self):
|
||||
if not self.generators.get('base'):
|
||||
from ldm.dream.generator import Generator
|
||||
from ldm.invoke.generator import Generator
|
||||
self.generators['base'] = Generator(self.model, self.precision)
|
||||
return self.generators['base']
|
||||
|
||||
def _make_img2img(self):
|
||||
if not self.generators.get('img2img'):
|
||||
from ldm.dream.generator.img2img import Img2Img
|
||||
from ldm.invoke.generator.img2img import Img2Img
|
||||
self.generators['img2img'] = Img2Img(self.model, self.precision)
|
||||
return self.generators['img2img']
|
||||
|
||||
def _make_embiggen(self):
|
||||
if not self.generators.get('embiggen'):
|
||||
from ldm.dream.generator.embiggen import Embiggen
|
||||
from ldm.invoke.generator.embiggen import Embiggen
|
||||
self.generators['embiggen'] = Embiggen(self.model, self.precision)
|
||||
return self.generators['embiggen']
|
||||
|
||||
def _make_txt2img(self):
|
||||
if not self.generators.get('txt2img'):
|
||||
from ldm.dream.generator.txt2img import Txt2Img
|
||||
from ldm.invoke.generator.txt2img import Txt2Img
|
||||
self.generators['txt2img'] = Txt2Img(self.model, self.precision)
|
||||
self.generators['txt2img'].free_gpu_mem = self.free_gpu_mem
|
||||
return self.generators['txt2img']
|
||||
|
||||
def _make_txt2img2img(self):
|
||||
if not self.generators.get('txt2img2'):
|
||||
from ldm.dream.generator.txt2img2img import Txt2Img2Img
|
||||
from ldm.invoke.generator.txt2img2img import Txt2Img2Img
|
||||
self.generators['txt2img2'] = Txt2Img2Img(self.model, self.precision)
|
||||
self.generators['txt2img2'].free_gpu_mem = self.free_gpu_mem
|
||||
return self.generators['txt2img2']
|
||||
|
||||
def _make_inpaint(self):
|
||||
if not self.generators.get('inpaint'):
|
||||
from ldm.dream.generator.inpaint import Inpaint
|
||||
from ldm.invoke.generator.inpaint import Inpaint
|
||||
self.generators['inpaint'] = Inpaint(self.model, self.precision)
|
||||
return self.generators['inpaint']
|
||||
|
||||
@ -784,7 +761,7 @@ class Generate:
|
||||
|
||||
print(msg)
|
||||
|
||||
# Be warned: config is the path to the model config file, not the dream conf file!
|
||||
# Be warned: config is the path to the model config file, not the invoke conf file!
|
||||
# Also note that we can get config and weights from self, so why do we need to
|
||||
# pass them as args?
|
||||
def _load_model_from_config(self, config, weights):
|
||||
@ -920,6 +897,17 @@ class Generate:
|
||||
colored += 1
|
||||
return colored == 0
|
||||
|
||||
def _transparency_check_and_warning(self,image, mask):
|
||||
if not mask:
|
||||
print(
|
||||
'>> Initial image has transparent areas. Will inpaint in these regions.')
|
||||
if self._check_for_erasure(image):
|
||||
print(
|
||||
'>> WARNING: Colors underneath the transparent region seem to have been erased.\n',
|
||||
'>> Inpainting will be suboptimal. Please preserve the colors when making\n',
|
||||
'>> a transparency mask, or provide mask explicitly using --init_mask (-M).'
|
||||
)
|
||||
|
||||
def _squeeze_image(self, image):
|
||||
x, y, resize_needed = self._resolution_check(image.width, image.height)
|
||||
if resize_needed:
|
||||
|
@ -1,7 +1,7 @@
|
||||
"""Helper class for dealing with image generation arguments.
|
||||
|
||||
The Args class parses both the command line (shell) arguments, as well as the
|
||||
command string passed at the dream> prompt. It serves as the definitive repository
|
||||
command string passed at the invoke> prompt. It serves as the definitive repository
|
||||
of all the arguments used by Generate and their default values, and implements the
|
||||
preliminary metadata standards discussed here:
|
||||
|
||||
@ -19,7 +19,7 @@ To use:
|
||||
print('oops')
|
||||
sys.exit(-1)
|
||||
|
||||
# read in a command passed to the dream> prompt:
|
||||
# read in a command passed to the invoke> prompt:
|
||||
opts = opt.parse_cmd('do androids dream of electric sheep? -H256 -W1024 -n4')
|
||||
|
||||
# The Args object acts like a namespace object
|
||||
@ -64,7 +64,7 @@ To generate a dict representing RFC266 metadata:
|
||||
This will generate an RFC266 dictionary that can then be turned into a JSON
|
||||
and written to the PNG file. The optional seeds, weights, model_hash and
|
||||
postprocesser arguments are not available to the opt object and so must be
|
||||
provided externally. See how dream.py does it.
|
||||
provided externally. See how invoke.py does it.
|
||||
|
||||
Note that this function was originally called format_metadata() and a wrapper
|
||||
is provided that issues a deprecation notice.
|
||||
@ -91,8 +91,8 @@ import re
|
||||
import copy
|
||||
import base64
|
||||
import functools
|
||||
import ldm.dream.pngwriter
|
||||
from ldm.dream.conditioning import split_weighted_subprompts
|
||||
import ldm.invoke.pngwriter
|
||||
from ldm.invoke.conditioning import split_weighted_subprompts
|
||||
|
||||
SAMPLER_CHOICES = [
|
||||
'ddim',
|
||||
@ -151,7 +151,7 @@ class Args(object):
|
||||
'''
|
||||
Initialize new Args class. It takes two optional arguments, an argparse
|
||||
parser for switches given on the shell command line, and an argparse
|
||||
parser for switches given on the dream> CLI line. If one or both are
|
||||
parser for switches given on the invoke> CLI line. If one or both are
|
||||
missing, it creates appropriate parsers internally.
|
||||
'''
|
||||
self._arg_parser = arg_parser or self._create_arg_parser()
|
||||
@ -168,7 +168,7 @@ class Args(object):
|
||||
return None
|
||||
|
||||
def parse_cmd(self,cmd_string):
|
||||
'''Parse a dream>-style command string '''
|
||||
'''Parse a invoke>-style command string '''
|
||||
command = cmd_string.replace("'", "\\'")
|
||||
try:
|
||||
elements = shlex.split(command)
|
||||
@ -269,7 +269,7 @@ class Args(object):
|
||||
if a['with_variations']:
|
||||
formatted_variations = ','.join(f'{seed}:{weight}' for seed, weight in (a["with_variations"]))
|
||||
switches.append(f'-V {formatted_variations}')
|
||||
if 'variations' in a:
|
||||
if 'variations' in a and len(a['variations'])>0:
|
||||
switches.append(f'-V {a["variations"]}')
|
||||
return ' '.join(switches)
|
||||
|
||||
@ -509,23 +509,23 @@ class Args(object):
|
||||
)
|
||||
return parser
|
||||
|
||||
# This creates the parser that processes commands on the dream> command line
|
||||
# This creates the parser that processes commands on the invoke> command line
|
||||
def _create_dream_cmd_parser(self):
|
||||
parser = PagingArgumentParser(
|
||||
formatter_class=ArgFormatter,
|
||||
description=
|
||||
"""
|
||||
*Image generation:*
|
||||
dream> a fantastic alien landscape -W576 -H512 -s60 -n4
|
||||
invoke> a fantastic alien landscape -W576 -H512 -s60 -n4
|
||||
|
||||
*postprocessing*
|
||||
!fix applies upscaling/facefixing to a previously-generated image.
|
||||
dream> !fix 0000045.4829112.png -G1 -U4 -ft codeformer
|
||||
invoke> !fix 0000045.4829112.png -G1 -U4 -ft codeformer
|
||||
|
||||
*History manipulation*
|
||||
!fetch retrieves the command used to generate an earlier image.
|
||||
dream> !fetch 0000015.8929913.png
|
||||
dream> a fantastic alien landscape -W 576 -H 512 -s 60 -A plms -C 7.5
|
||||
invoke> !fetch 0000015.8929913.png
|
||||
invoke> a fantastic alien landscape -W 576 -H 512 -s 60 -A plms -C 7.5
|
||||
|
||||
!history lists all the commands issued during the current session.
|
||||
|
||||
@ -842,7 +842,7 @@ def metadata_from_png(png_file_path) -> Args:
|
||||
an Args object containing the image metadata. Note that this
|
||||
returns a single Args object, not multiple.
|
||||
'''
|
||||
meta = ldm.dream.pngwriter.retrieve_metadata(png_file_path)
|
||||
meta = ldm.invoke.pngwriter.retrieve_metadata(png_file_path)
|
||||
if 'sd-metadata' in meta and len(meta['sd-metadata'])>0 :
|
||||
return metadata_loads(meta)[0]
|
||||
else:
|
4
ldm/invoke/generator/__init__.py
Normal file
@ -0,0 +1,4 @@
|
||||
'''
|
||||
Initialization file for the ldm.invoke.generator package
|
||||
'''
|
||||
from .base import Generator
|
@ -1,5 +1,5 @@
|
||||
'''
|
||||
Base class for ldm.dream.generator.*
|
||||
Base class for ldm.invoke.generator.*
|
||||
including img2img, txt2img, and inpaint
|
||||
'''
|
||||
import torch
|
||||
@ -9,7 +9,7 @@ from tqdm import tqdm, trange
|
||||
from PIL import Image
|
||||
from einops import rearrange, repeat
|
||||
from pytorch_lightning import seed_everything
|
||||
from ldm.dream.devices import choose_autocast
|
||||
from ldm.invoke.devices import choose_autocast
|
||||
from ldm.util import rand_perlin_2d
|
||||
|
||||
downsampling = 8
|
||||
@ -21,6 +21,8 @@ class Generator():
|
||||
self.seed = None
|
||||
self.latent_channels = model.channels
|
||||
self.downsampling_factor = downsampling # BUG: should come from model or config
|
||||
self.perlin = 0.0
|
||||
self.threshold = 0
|
||||
self.variation_amount = 0
|
||||
self.with_variations = []
|
||||
|
@ -1,15 +1,15 @@
|
||||
'''
|
||||
ldm.dream.generator.embiggen descends from ldm.dream.generator
|
||||
and generates with ldm.dream.generator.img2img
|
||||
ldm.invoke.generator.embiggen descends from ldm.invoke.generator
|
||||
and generates with ldm.invoke.generator.img2img
|
||||
'''
|
||||
|
||||
import torch
|
||||
import numpy as np
|
||||
from tqdm import trange
|
||||
from PIL import Image
|
||||
from ldm.dream.generator.base import Generator
|
||||
from ldm.dream.generator.img2img import Img2Img
|
||||
from ldm.dream.devices import choose_autocast
|
||||
from ldm.invoke.generator.base import Generator
|
||||
from ldm.invoke.generator.img2img import Img2Img
|
||||
from ldm.invoke.devices import choose_autocast
|
||||
from ldm.models.diffusion.ddim import DDIMSampler
|
||||
|
||||
class Embiggen(Generator):
|
||||
@ -107,7 +107,7 @@ class Embiggen(Generator):
|
||||
initsuperwidth = round(initsuperwidth*embiggen[0])
|
||||
initsuperheight = round(initsuperheight*embiggen[0])
|
||||
if embiggen[1] > 0: # No point in ESRGAN upscaling if strength is set zero
|
||||
from ldm.dream.restoration.realesrgan import ESRGAN
|
||||
from ldm.invoke.restoration.realesrgan import ESRGAN
|
||||
esrgan = ESRGAN()
|
||||
print(
|
||||
f'>> ESRGAN upscaling init image prior to cutting with Embiggen with strength {embiggen[1]}')
|
@ -1,11 +1,11 @@
|
||||
'''
|
||||
ldm.dream.generator.img2img descends from ldm.dream.generator
|
||||
ldm.invoke.generator.img2img descends from ldm.invoke.generator
|
||||
'''
|
||||
|
||||
import torch
|
||||
import numpy as np
|
||||
from ldm.dream.devices import choose_autocast
|
||||
from ldm.dream.generator.base import Generator
|
||||
from ldm.invoke.devices import choose_autocast
|
||||
from ldm.invoke.generator.base import Generator
|
||||
from ldm.models.diffusion.ddim import DDIMSampler
|
||||
|
||||
class Img2Img(Generator):
|
@ -1,12 +1,12 @@
|
||||
'''
|
||||
ldm.dream.generator.inpaint descends from ldm.dream.generator
|
||||
ldm.invoke.generator.inpaint descends from ldm.invoke.generator
|
||||
'''
|
||||
|
||||
import torch
|
||||
import numpy as np
|
||||
from einops import rearrange, repeat
|
||||
from ldm.dream.devices import choose_autocast
|
||||
from ldm.dream.generator.img2img import Img2Img
|
||||
from ldm.invoke.devices import choose_autocast
|
||||
from ldm.invoke.generator.img2img import Img2Img
|
||||
from ldm.models.diffusion.ddim import DDIMSampler
|
||||
from ldm.models.diffusion.ksampler import KSampler
|
||||
|
||||
@ -27,7 +27,7 @@ class Inpaint(Img2Img):
|
||||
# klms samplers not supported yet, so ignore previous sampler
|
||||
if isinstance(sampler,KSampler):
|
||||
print(
|
||||
f">> sampler '{sampler.__class__.__name__}' is not yet supported for inpainting, using DDIMSampler instead."
|
||||
f">> Using recommended DDIM sampler for inpainting."
|
||||
)
|
||||
sampler = DDIMSampler(self.model, device=self.model.device)
|
||||
|
@ -1,10 +1,10 @@
|
||||
'''
|
||||
ldm.dream.generator.txt2img inherits from ldm.dream.generator
|
||||
ldm.invoke.generator.txt2img inherits from ldm.invoke.generator
|
||||
'''
|
||||
|
||||
import torch
|
||||
import numpy as np
|
||||
from ldm.dream.generator.base import Generator
|
||||
from ldm.invoke.generator.base import Generator
|
||||
|
||||
class Txt2Img(Generator):
|
||||
def __init__(self, model, precision):
|
@ -1,11 +1,11 @@
|
||||
'''
|
||||
ldm.dream.generator.txt2img inherits from ldm.dream.generator
|
||||
ldm.invoke.generator.txt2img inherits from ldm.invoke.generator
|
||||
'''
|
||||
|
||||
import torch
|
||||
import numpy as np
|
||||
import math
|
||||
from ldm.dream.generator.base import Generator
|
||||
from ldm.invoke.generator.base import Generator
|
||||
from ldm.models.diffusion.ddim import DDIMSampler
|
||||
|
||||
|
||||
@ -64,7 +64,7 @@ class Txt2Img2Img(Generator):
|
||||
)
|
||||
|
||||
print(
|
||||
f"\n>> Interpolating from {init_width}x{init_height} to {width}x{height}"
|
||||
f"\n>> Interpolating from {init_width}x{init_height} to {width}x{height} using DDIM sampling"
|
||||
)
|
||||
|
||||
# resizing
|
||||
@ -75,17 +75,19 @@ class Txt2Img2Img(Generator):
|
||||
)
|
||||
|
||||
t_enc = int(strength * steps)
|
||||
ddim_sampler = DDIMSampler(self.model, device=self.model.device)
|
||||
ddim_sampler.make_schedule(
|
||||
ddim_num_steps=steps, ddim_eta=ddim_eta, verbose=False
|
||||
)
|
||||
|
||||
x = self.get_noise(width,height,False)
|
||||
|
||||
z_enc = sampler.stochastic_encode(
|
||||
z_enc = ddim_sampler.stochastic_encode(
|
||||
samples,
|
||||
torch.tensor([t_enc]).to(self.model.device),
|
||||
noise=x
|
||||
noise=self.get_noise(width,height,False)
|
||||
)
|
||||
|
||||
# decode it
|
||||
samples = sampler.decode(
|
||||
samples = ddim_sampler.decode(
|
||||
z_enc,
|
||||
c,
|
||||
t_enc,
|
@ -1,17 +1,17 @@
|
||||
"""
|
||||
Readline helper functions for dream.py (linux and mac only).
|
||||
Readline helper functions for invoke.py.
|
||||
You may import the global singleton `completer` to get access to the
|
||||
completer object itself. This is useful when you want to autocomplete
|
||||
seeds:
|
||||
|
||||
from ldm.dream.readline import completer
|
||||
from ldm.invoke.readline import completer
|
||||
completer.add_seed(18247566)
|
||||
completer.add_seed(9281839)
|
||||
"""
|
||||
import os
|
||||
import re
|
||||
import atexit
|
||||
from ldm.dream.args import Args
|
||||
from ldm.invoke.args import Args
|
||||
|
||||
# ---------------readline utilities---------------------
|
||||
try:
|
||||
@ -20,7 +20,7 @@ try:
|
||||
except (ImportError,ModuleNotFoundError):
|
||||
readline_available = False
|
||||
|
||||
IMG_EXTENSIONS = ('.png','.jpg','.jpeg')
|
||||
IMG_EXTENSIONS = ('.png','.jpg','.jpeg','.PNG','.JPG','.JPEG','.gif','.GIF')
|
||||
COMMANDS = (
|
||||
'--steps','-s',
|
||||
'--seed','-S',
|
||||
@ -74,7 +74,7 @@ class Completer(object):
|
||||
|
||||
def complete(self, text, state):
|
||||
'''
|
||||
Completes dream command line.
|
||||
Completes invoke command line.
|
||||
BUG: it doesn't correctly complete files that have spaces in the name.
|
||||
'''
|
||||
buffer = readline.get_line_buffer()
|
||||
@ -287,7 +287,7 @@ def get_completer(opt:Args)->Completer:
|
||||
readline.parse_and_bind('set skip-completed-text on')
|
||||
readline.parse_and_bind('set show-all-if-ambiguous on')
|
||||
|
||||
histfile = os.path.join(os.path.expanduser(opt.outdir), '.dream_history')
|
||||
histfile = os.path.join(os.path.expanduser(opt.outdir), '.invoke_history')
|
||||
try:
|
||||
readline.read_history_file(histfile)
|
||||
readline.set_history_length(1000)
|
4
ldm/invoke/restoration/__init__.py
Normal file
@ -0,0 +1,4 @@
|
||||
'''
|
||||
Initialization file for the ldm.invoke.restoration package
|
||||
'''
|
||||
from .base import Restoration
|
@ -23,16 +23,16 @@ class Restoration():
|
||||
|
||||
# Face Restore Models
|
||||
def load_gfpgan(self, gfpgan_dir, gfpgan_model_path):
|
||||
from ldm.dream.restoration.gfpgan import GFPGAN
|
||||
from ldm.invoke.restoration.gfpgan import GFPGAN
|
||||
return GFPGAN(gfpgan_dir, gfpgan_model_path)
|
||||
|
||||
def load_codeformer(self):
|
||||
from ldm.dream.restoration.codeformer import CodeFormerRestoration
|
||||
from ldm.invoke.restoration.codeformer import CodeFormerRestoration
|
||||
return CodeFormerRestoration()
|
||||
|
||||
# Upscale Models
|
||||
def load_esrgan(self, esrgan_bg_tile=400):
|
||||
from ldm.dream.restoration.realesrgan import ESRGAN
|
||||
from ldm.invoke.restoration.realesrgan import ESRGAN
|
||||
esrgan = ESRGAN(esrgan_bg_tile)
|
||||
print('>> ESRGAN Initialized')
|
||||
return esrgan;
|
@ -8,7 +8,7 @@ pretrained_model_url = 'https://github.com/sczhou/CodeFormer/releases/download/v
|
||||
|
||||
class CodeFormerRestoration():
|
||||
def __init__(self,
|
||||
codeformer_dir='ldm/dream/restoration/codeformer',
|
||||
codeformer_dir='ldm/invoke/restoration/codeformer',
|
||||
codeformer_model_path='weights/codeformer.pth') -> None:
|
||||
self.model_path = os.path.join(codeformer_dir, codeformer_model_path)
|
||||
self.codeformer_model_exists = os.path.isfile(self.model_path)
|
||||
@ -27,7 +27,7 @@ class CodeFormerRestoration():
|
||||
from basicsr.utils.download_util import load_file_from_url
|
||||
from basicsr.utils import img2tensor, tensor2img
|
||||
from facexlib.utils.face_restoration_helper import FaceRestoreHelper
|
||||
from ldm.dream.restoration.codeformer_arch import CodeFormer
|
||||
from ldm.invoke.restoration.codeformer_arch import CodeFormer
|
||||
from torchvision.transforms.functional import normalize
|
||||
from PIL import Image
|
||||
|
||||
@ -35,7 +35,7 @@ class CodeFormerRestoration():
|
||||
|
||||
cf = cf_class(dim_embd=512, codebook_size=1024, n_head=8, n_layers=9, connect_list=['32', '64', '128', '256']).to(device)
|
||||
|
||||
checkpoint_path = load_file_from_url(url=pretrained_model_url, model_dir=os.path.abspath('ldm/dream/restoration/codeformer/weights'), progress=True)
|
||||
checkpoint_path = load_file_from_url(url=pretrained_model_url, model_dir=os.path.abspath('ldm/invoke/restoration/codeformer/weights'), progress=True)
|
||||
checkpoint = torch.load(checkpoint_path)['params_ema']
|
||||
cf.load_state_dict(checkpoint)
|
||||
cf.eval()
|
@ -5,7 +5,7 @@ from torch import nn, Tensor
|
||||
import torch.nn.functional as F
|
||||
from typing import Optional, List
|
||||
|
||||
from ldm.dream.restoration.vqgan_arch import *
|
||||
from ldm.invoke.restoration.vqgan_arch import *
|
||||
from basicsr.utils import get_root_logger
|
||||
from basicsr.utils.registry import ARCH_REGISTRY
|
||||
|
@ -13,8 +13,6 @@ class Outpaint(object):
|
||||
seed = old_opt.seed
|
||||
prompt = old_opt.prompt
|
||||
|
||||
print(f'DEBUG: old seed={seed}, old prompt = {prompt}')
|
||||
|
||||
def wrapped_callback(img,seed,**kwargs):
|
||||
image_callback(img,seed,use_prefix=prefix,**kwargs)
|
||||
|
@ -4,9 +4,9 @@ import copy
|
||||
import base64
|
||||
import mimetypes
|
||||
import os
|
||||
from ldm.dream.args import Args, metadata_dumps
|
||||
from ldm.invoke.args import Args, metadata_dumps
|
||||
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
||||
from ldm.dream.pngwriter import PngWriter
|
||||
from ldm.invoke.pngwriter import PngWriter
|
||||
from threading import Event
|
||||
|
||||
def build_opt(post_data, seed, gfpgan_model_exists):
|
@ -4,7 +4,7 @@ import torch
|
||||
import numpy as np
|
||||
from tqdm import tqdm
|
||||
from functools import partial
|
||||
from ldm.dream.devices import choose_torch_device
|
||||
from ldm.invoke.devices import choose_torch_device
|
||||
from ldm.models.diffusion.sampler import Sampler
|
||||
from ldm.modules.diffusionmodules.util import noise_like
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
import k_diffusion as K
|
||||
import torch
|
||||
import torch.nn as nn
|
||||
from ldm.dream.devices import choose_torch_device
|
||||
from ldm.invoke.devices import choose_torch_device
|
||||
from ldm.models.diffusion.sampler import Sampler
|
||||
from ldm.util import rand_perlin_2d
|
||||
from ldm.modules.diffusionmodules.util import (
|
||||
@ -57,8 +57,9 @@ class KSampler(Sampler):
|
||||
schedule,
|
||||
steps=model.num_timesteps,
|
||||
)
|
||||
self.ds = None
|
||||
self.s_in = None
|
||||
self.sigmas = None
|
||||
self.ds = None
|
||||
self.s_in = None
|
||||
|
||||
def forward(self, x, sigma, uncond, cond, cond_scale):
|
||||
x_in = torch.cat([x] * 2)
|
||||
@ -190,7 +191,7 @@ class KSampler(Sampler):
|
||||
'uncond': unconditional_conditioning,
|
||||
'cond_scale': unconditional_guidance_scale,
|
||||
}
|
||||
print(f'>> Sampling with k_{self.schedule}')
|
||||
print(f'>> Sampling with k_{self.schedule} starting at step {len(self.sigmas)-S-1} of {len(self.sigmas)-1} ({S} new sampling steps)')
|
||||
return (
|
||||
K.sampling.__dict__[f'sample_{self.schedule}'](
|
||||
model_wrap_cfg, x, sigmas, extra_args=extra_args,
|
||||
@ -199,6 +200,8 @@ class KSampler(Sampler):
|
||||
None,
|
||||
)
|
||||
|
||||
# this code will support inpainting if and when ksampler API modified or
|
||||
# a workaround is found.
|
||||
@torch.no_grad()
|
||||
def p_sample(
|
||||
self,
|
||||
|
@ -4,7 +4,7 @@ import torch
|
||||
import numpy as np
|
||||
from tqdm import tqdm
|
||||
from functools import partial
|
||||
from ldm.dream.devices import choose_torch_device
|
||||
from ldm.invoke.devices import choose_torch_device
|
||||
from ldm.models.diffusion.sampler import Sampler
|
||||
from ldm.modules.diffusionmodules.util import noise_like
|
||||
|
||||
|
@ -8,7 +8,7 @@ import torch
|
||||
import numpy as np
|
||||
from tqdm import tqdm
|
||||
from functools import partial
|
||||
from ldm.dream.devices import choose_torch_device
|
||||
from ldm.invoke.devices import choose_torch_device
|
||||
|
||||
from ldm.modules.diffusionmodules.util import (
|
||||
make_ddim_sampling_parameters,
|
||||
|
@ -5,7 +5,7 @@ import clip
|
||||
from einops import rearrange, repeat
|
||||
from transformers import CLIPTokenizer, CLIPTextModel
|
||||
import kornia
|
||||
from ldm.dream.devices import choose_torch_device
|
||||
from ldm.invoke.devices import choose_torch_device
|
||||
|
||||
from ldm.modules.x_transformer import (
|
||||
Encoder,
|
||||
|
@ -14,7 +14,7 @@ from ldm.models.diffusion.ddim import DDIMSampler
|
||||
from ldm.util import ismap
|
||||
import time
|
||||
from omegaconf import OmegaConf
|
||||
from ldm.dream.devices import choose_torch_device
|
||||
from ldm.invoke.devices import choose_torch_device
|
||||
|
||||
def download_models(mode):
|
||||
|
||||
|
@ -20,6 +20,6 @@ torchmetrics==0.6.0
|
||||
transformers==4.19.2
|
||||
-e git+https://github.com/openai/CLIP.git@main#egg=clip
|
||||
-e git+https://github.com/CompVis/taming-transformers.git@master#egg=taming-transformers
|
||||
git+https://github.com/lstein/k-diffusion.git@master#egg=k-diffusion
|
||||
-e git+https://github.com/lstein/GFPGAN@fix-dark-cast-images#egg=gfpgan
|
||||
-e .
|
||||
-e git+https://github.com/lstein/k-diffusion.git@master#egg=k-diffusion
|
||||
-e git+https://github.com/TencentARC/GFPGAN.git#egg=gfpgan
|
||||
-e .
|
||||
|
@ -1,8 +1,5 @@
|
||||
-r requirements.txt
|
||||
|
||||
--pre
|
||||
--extra-index-url https://download.pytorch.org/whl/nightly/cpu --trusted-host https://download.pytorch.org
|
||||
|
||||
protobuf==3.19.4
|
||||
torch
|
||||
torchvision
|
||||
|
@ -31,6 +31,7 @@ flaskwebgui==0.3.7
|
||||
send2trash
|
||||
dependency_injector==4.40.0
|
||||
eventlet
|
||||
realesrgan
|
||||
git+https://github.com/openai/CLIP.git@main#egg=clip
|
||||
git+https://github.com/Birch-san/k-diffusion.git@mps#egg=k-diffusion
|
||||
git+https://github.com/lstein/GFPGAN@fix-dark-cast-images#egg=gfpgan
|
||||
git+https://github.com/TencentARC/GFPGAN.git#egg=gfpgan
|
||||
|
571
scripts/dream.py
@ -1,571 +1,12 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2022 Lincoln D. Stein (https://github.com/lstein)
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import shlex
|
||||
import copy
|
||||
import warnings
|
||||
import time
|
||||
import traceback
|
||||
sys.path.append('.') # corrects a weird problem on Macs
|
||||
from ldm.dream.readline import get_completer
|
||||
from ldm.dream.args import Args, metadata_dumps, metadata_from_png, dream_cmd_from_png
|
||||
from ldm.dream.pngwriter import PngWriter, retrieve_metadata, write_metadata
|
||||
from ldm.dream.image_util import make_grid
|
||||
from ldm.dream.log import write_log
|
||||
from omegaconf import OmegaConf
|
||||
from backend.invoke_ai_web_server import InvokeAIWebServer
|
||||
import os.path
|
||||
|
||||
script_path = sys.argv[0]
|
||||
script_args = sys.argv[1:]
|
||||
script_dir,script_name = os.path.split(script_path)
|
||||
script_dest = os.path.join(script_dir,'invoke.py')
|
||||
os.execlp('python3','python3',script_dest,*script_args)
|
||||
|
||||
def main():
|
||||
"""Initialize command-line parsers and the diffusion model"""
|
||||
opt = Args()
|
||||
args = opt.parse_args()
|
||||
if not args:
|
||||
sys.exit(-1)
|
||||
|
||||
if args.laion400m:
|
||||
print('--laion400m flag has been deprecated. Please use --model laion400m instead.')
|
||||
sys.exit(-1)
|
||||
if args.weights:
|
||||
print('--weights argument has been deprecated. Please edit ./configs/models.yaml, and select the weights using --model instead.')
|
||||
sys.exit(-1)
|
||||
|
||||
print('* Initializing, be patient...\n')
|
||||
from ldm.generate import Generate
|
||||
|
||||
# these two lines prevent a horrible warning message from appearing
|
||||
# when the frozen CLIP tokenizer is imported
|
||||
import transformers
|
||||
transformers.logging.set_verbosity_error()
|
||||
|
||||
# Loading Face Restoration and ESRGAN Modules
|
||||
try:
|
||||
gfpgan, codeformer, esrgan = None, None, None
|
||||
if opt.restore or opt.esrgan:
|
||||
from ldm.dream.restoration import Restoration
|
||||
restoration = Restoration()
|
||||
if opt.restore:
|
||||
gfpgan, codeformer = restoration.load_face_restore_models(opt.gfpgan_dir, opt.gfpgan_model_path)
|
||||
else:
|
||||
print('>> Face restoration disabled')
|
||||
if opt.esrgan:
|
||||
esrgan = restoration.load_esrgan(opt.esrgan_bg_tile)
|
||||
else:
|
||||
print('>> Upscaling disabled')
|
||||
else:
|
||||
print('>> Face restoration and upscaling disabled')
|
||||
except (ModuleNotFoundError, ImportError):
|
||||
print(traceback.format_exc(), file=sys.stderr)
|
||||
print('>> You may need to install the ESRGAN and/or GFPGAN modules')
|
||||
|
||||
# creating a simple text2image object with a handful of
|
||||
# defaults passed on the command line.
|
||||
# additional parameters will be added (or overriden) during
|
||||
# the user input loop
|
||||
try:
|
||||
gen = Generate(
|
||||
conf = opt.conf,
|
||||
model = opt.model,
|
||||
sampler_name = opt.sampler_name,
|
||||
embedding_path = opt.embedding_path,
|
||||
full_precision = opt.full_precision,
|
||||
precision = opt.precision,
|
||||
gfpgan=gfpgan,
|
||||
codeformer=codeformer,
|
||||
esrgan=esrgan
|
||||
)
|
||||
except (FileNotFoundError, IOError, KeyError) as e:
|
||||
print(f'{e}. Aborting.')
|
||||
sys.exit(-1)
|
||||
|
||||
# make sure the output directory exists
|
||||
if not os.path.exists(opt.outdir):
|
||||
os.makedirs(opt.outdir)
|
||||
|
||||
# load the infile as a list of lines
|
||||
infile = None
|
||||
if opt.infile:
|
||||
try:
|
||||
if os.path.isfile(opt.infile):
|
||||
infile = open(opt.infile, 'r', encoding='utf-8')
|
||||
elif opt.infile == '-': # stdin
|
||||
infile = sys.stdin
|
||||
else:
|
||||
raise FileNotFoundError(f'{opt.infile} not found.')
|
||||
except (FileNotFoundError, IOError) as e:
|
||||
print(f'{e}. Aborting.')
|
||||
sys.exit(-1)
|
||||
|
||||
if opt.seamless:
|
||||
print(">> changed to seamless tiling mode")
|
||||
|
||||
# preload the model
|
||||
gen.load_model()
|
||||
#set additional option
|
||||
gen.free_gpu_mem = opt.free_gpu_mem
|
||||
|
||||
# web server loops forever
|
||||
if opt.web or opt.gui:
|
||||
invoke_ai_web_server_loop(gen, gfpgan, codeformer, esrgan)
|
||||
sys.exit(0)
|
||||
|
||||
if not infile:
|
||||
print(
|
||||
"\n* Initialization done! Awaiting your command (-h for help, 'q' to quit)"
|
||||
)
|
||||
|
||||
main_loop(gen, opt, infile)
|
||||
|
||||
# TODO: main_loop() has gotten busy. Needs to be refactored.
|
||||
def main_loop(gen, opt, infile):
|
||||
"""prompt/read/execute loop"""
|
||||
done = False
|
||||
path_filter = re.compile(r'[<>:"/\\|?*]')
|
||||
last_results = list()
|
||||
model_config = OmegaConf.load(opt.conf)[opt.model]
|
||||
|
||||
# The readline completer reads history from the .dream_history file located in the
|
||||
# output directory specified at the time of script launch. We do not currently support
|
||||
# changing the history file midstream when the output directory is changed.
|
||||
completer = get_completer(opt)
|
||||
output_cntr = completer.get_current_history_length()+1
|
||||
|
||||
# os.pathconf is not available on Windows
|
||||
if hasattr(os, 'pathconf'):
|
||||
path_max = os.pathconf(opt.outdir, 'PC_PATH_MAX')
|
||||
name_max = os.pathconf(opt.outdir, 'PC_NAME_MAX')
|
||||
else:
|
||||
path_max = 260
|
||||
name_max = 255
|
||||
|
||||
while not done:
|
||||
operation = 'generate' # default operation, alternative is 'postprocess'
|
||||
|
||||
if completer:
|
||||
completer.set_default_dir(opt.outdir)
|
||||
|
||||
try:
|
||||
command = get_next_command(infile)
|
||||
except EOFError:
|
||||
done = True
|
||||
continue
|
||||
|
||||
# skip empty lines
|
||||
if not command.strip():
|
||||
continue
|
||||
|
||||
if command.startswith(('#', '//')):
|
||||
continue
|
||||
|
||||
if len(command.strip()) == 1 and command.startswith('q'):
|
||||
done = True
|
||||
break
|
||||
|
||||
if command.startswith('!'):
|
||||
subcommand = command[1:]
|
||||
|
||||
if subcommand.startswith('dream'): # in case a stored prompt still contains the !dream command
|
||||
command = command.replace('!dream ','',1)
|
||||
|
||||
elif subcommand.startswith('fix'):
|
||||
command = command.replace('!fix ','',1)
|
||||
operation = 'postprocess'
|
||||
|
||||
elif subcommand.startswith('fetch'):
|
||||
file_path = command.replace('!fetch ','',1)
|
||||
retrieve_dream_command(opt,file_path,completer)
|
||||
continue
|
||||
|
||||
elif subcommand.startswith('history'):
|
||||
completer.show_history()
|
||||
continue
|
||||
|
||||
elif subcommand.startswith('search'):
|
||||
search_str = command.replace('!search ','',1)
|
||||
completer.show_history(search_str)
|
||||
continue
|
||||
|
||||
elif subcommand.startswith('clear'):
|
||||
completer.clear_history()
|
||||
continue
|
||||
|
||||
elif re.match('^(\d+)',subcommand):
|
||||
command_no = re.match('^(\d+)',subcommand).groups()[0]
|
||||
command = completer.get_line(int(command_no))
|
||||
completer.set_line(command)
|
||||
continue
|
||||
|
||||
else: # not a recognized subcommand, so give the --help text
|
||||
command = '-h'
|
||||
|
||||
if opt.parse_cmd(command) is None:
|
||||
continue
|
||||
|
||||
if opt.init_img:
|
||||
try:
|
||||
if not opt.prompt:
|
||||
oldargs = metadata_from_png(opt.init_img)
|
||||
opt.prompt = oldargs.prompt
|
||||
print(f'>> Retrieved old prompt "{opt.prompt}" from {opt.init_img}')
|
||||
except (OSError, AttributeError, KeyError):
|
||||
pass
|
||||
|
||||
if len(opt.prompt) == 0:
|
||||
print('\nTry again with a prompt!')
|
||||
continue
|
||||
|
||||
# width and height are set by model if not specified
|
||||
if not opt.width:
|
||||
opt.width = model_config.width
|
||||
if not opt.height:
|
||||
opt.height = model_config.height
|
||||
|
||||
# retrieve previous value of init image if requested
|
||||
if opt.init_img is not None and re.match('^-\\d+$', opt.init_img):
|
||||
try:
|
||||
opt.init_img = last_results[int(opt.init_img)][0]
|
||||
print(f'>> Reusing previous image {opt.init_img}')
|
||||
except IndexError:
|
||||
print(
|
||||
f'>> No previous initial image at position {opt.init_img} found')
|
||||
opt.init_img = None
|
||||
continue
|
||||
|
||||
# try to relativize pathnames
|
||||
for attr in ('init_img','init_mask','init_color','embedding_path'):
|
||||
if getattr(opt,attr) and not os.path.exists(getattr(opt,attr)):
|
||||
basename = getattr(opt,attr)
|
||||
path = os.path.join(opt.outdir,basename)
|
||||
setattr(opt,attr,path)
|
||||
|
||||
# retrieve previous value of seed if requested
|
||||
if opt.seed is not None and opt.seed < 0:
|
||||
try:
|
||||
opt.seed = last_results[opt.seed][1]
|
||||
print(f'>> Reusing previous seed {opt.seed}')
|
||||
except IndexError:
|
||||
print(f'>> No previous seed at position {opt.seed} found')
|
||||
opt.seed = None
|
||||
continue
|
||||
|
||||
if opt.strength is None:
|
||||
opt.strength = 0.75 if opt.out_direction is None else 0.83
|
||||
|
||||
if opt.with_variations is not None:
|
||||
opt.with_variations = split_variations(opt.with_variations)
|
||||
|
||||
if opt.prompt_as_dir:
|
||||
# sanitize the prompt to a valid folder name
|
||||
subdir = path_filter.sub('_', opt.prompt)[:name_max].rstrip(' .')
|
||||
|
||||
# truncate path to maximum allowed length
|
||||
# 39 is the length of '######.##########.##########-##.png', plus two separators and a NUL
|
||||
subdir = subdir[:(path_max - 39 - len(os.path.abspath(opt.outdir)))]
|
||||
current_outdir = os.path.join(opt.outdir, subdir)
|
||||
|
||||
print('Writing files to directory: "' + current_outdir + '"')
|
||||
|
||||
# make sure the output directory exists
|
||||
if not os.path.exists(current_outdir):
|
||||
os.makedirs(current_outdir)
|
||||
else:
|
||||
if not os.path.exists(opt.outdir):
|
||||
os.makedirs(opt.outdir)
|
||||
current_outdir = opt.outdir
|
||||
|
||||
# Here is where the images are actually generated!
|
||||
last_results = []
|
||||
try:
|
||||
file_writer = PngWriter(current_outdir)
|
||||
results = [] # list of filename, prompt pairs
|
||||
grid_images = dict() # seed -> Image, only used if `opt.grid`
|
||||
prior_variations = opt.with_variations or []
|
||||
prefix = file_writer.unique_prefix()
|
||||
|
||||
def image_writer(image, seed, upscaled=False, first_seed=None, use_prefix=None):
|
||||
# note the seed is the seed of the current image
|
||||
# the first_seed is the original seed that noise is added to
|
||||
# when the -v switch is used to generate variations
|
||||
nonlocal prior_variations
|
||||
nonlocal prefix
|
||||
if use_prefix is not None:
|
||||
prefix = use_prefix
|
||||
|
||||
path = None
|
||||
if opt.grid:
|
||||
grid_images[seed] = image
|
||||
else:
|
||||
postprocessed = upscaled if upscaled else operation=='postprocess'
|
||||
filename, formatted_dream_prompt = prepare_image_metadata(
|
||||
opt,
|
||||
prefix,
|
||||
seed,
|
||||
operation,
|
||||
prior_variations,
|
||||
postprocessed,
|
||||
first_seed
|
||||
)
|
||||
path = file_writer.save_image_and_prompt_to_png(
|
||||
image = image,
|
||||
dream_prompt = formatted_dream_prompt,
|
||||
metadata = metadata_dumps(
|
||||
opt,
|
||||
seeds = [seed if opt.variation_amount==0 and len(prior_variations)==0 else first_seed],
|
||||
model_hash = gen.model_hash,
|
||||
),
|
||||
name = filename,
|
||||
)
|
||||
|
||||
# update rfc metadata
|
||||
if operation == 'postprocess':
|
||||
tool = re.match('postprocess:(\w+)',opt.last_operation).groups()[0]
|
||||
add_postprocessing_to_metadata(
|
||||
opt,
|
||||
opt.prompt,
|
||||
filename,
|
||||
tool,
|
||||
formatted_dream_prompt,
|
||||
)
|
||||
|
||||
if (not postprocessed) or opt.save_original:
|
||||
# only append to results if we didn't overwrite an earlier output
|
||||
results.append([path, formatted_dream_prompt])
|
||||
|
||||
# so that the seed autocompletes (on linux|mac when -S or --seed specified
|
||||
if completer:
|
||||
completer.add_seed(seed)
|
||||
completer.add_seed(first_seed)
|
||||
last_results.append([path, seed])
|
||||
|
||||
if operation == 'generate':
|
||||
catch_ctrl_c = infile is None # if running interactively, we catch keyboard interrupts
|
||||
opt.last_operation='generate'
|
||||
gen.prompt2image(
|
||||
image_callback=image_writer,
|
||||
catch_interrupts=catch_ctrl_c,
|
||||
**vars(opt)
|
||||
)
|
||||
elif operation == 'postprocess':
|
||||
print(f'>> fixing {opt.prompt}')
|
||||
opt.last_operation = do_postprocess(gen,opt,image_writer)
|
||||
|
||||
if opt.grid and len(grid_images) > 0:
|
||||
grid_img = make_grid(list(grid_images.values()))
|
||||
grid_seeds = list(grid_images.keys())
|
||||
first_seed = last_results[0][1]
|
||||
filename = f'{prefix}.{first_seed}.png'
|
||||
formatted_dream_prompt = opt.dream_prompt_str(seed=first_seed,grid=True,iterations=len(grid_images))
|
||||
formatted_dream_prompt += f' # {grid_seeds}'
|
||||
metadata = metadata_dumps(
|
||||
opt,
|
||||
seeds = grid_seeds,
|
||||
model_hash = gen.model_hash
|
||||
)
|
||||
path = file_writer.save_image_and_prompt_to_png(
|
||||
image = grid_img,
|
||||
dream_prompt = formatted_dream_prompt,
|
||||
metadata = metadata,
|
||||
name = filename
|
||||
)
|
||||
results = [[path, formatted_dream_prompt]]
|
||||
|
||||
except AssertionError as e:
|
||||
print(e)
|
||||
continue
|
||||
|
||||
except OSError as e:
|
||||
print(e)
|
||||
continue
|
||||
|
||||
print('Outputs:')
|
||||
log_path = os.path.join(current_outdir, 'dream_log')
|
||||
output_cntr = write_log(results, log_path ,('txt', 'md'), output_cntr)
|
||||
print()
|
||||
if operation == 'postprocess':
|
||||
completer.add_history(f'!fix {command}')
|
||||
else:
|
||||
completer.add_history(command)
|
||||
|
||||
print('goodbye!')
|
||||
|
||||
def do_postprocess (gen, opt, callback):
|
||||
file_path = opt.prompt # treat the prompt as the file pathname
|
||||
if os.path.dirname(file_path) == '': #basename given
|
||||
file_path = os.path.join(opt.outdir,file_path)
|
||||
|
||||
tool=None
|
||||
if opt.gfpgan_strength > 0:
|
||||
tool = opt.facetool
|
||||
elif opt.embiggen:
|
||||
tool = 'embiggen'
|
||||
elif opt.upscale:
|
||||
tool = 'upscale'
|
||||
elif opt.out_direction:
|
||||
tool = 'outpaint'
|
||||
elif opt.outcrop:
|
||||
tool = 'outcrop'
|
||||
opt.save_original = True # do not overwrite old image!
|
||||
opt.last_operation = f'postprocess:{tool}'
|
||||
try:
|
||||
gen.apply_postprocessor(
|
||||
image_path = file_path,
|
||||
tool = tool,
|
||||
gfpgan_strength = opt.gfpgan_strength,
|
||||
codeformer_fidelity = opt.codeformer_fidelity,
|
||||
save_original = opt.save_original,
|
||||
upscale = opt.upscale,
|
||||
out_direction = opt.out_direction,
|
||||
outcrop = opt.outcrop,
|
||||
callback = callback,
|
||||
opt = opt,
|
||||
)
|
||||
except OSError:
|
||||
print(f'** {file_path}: file could not be read')
|
||||
return
|
||||
except (KeyError, AttributeError):
|
||||
print(traceback.format_exc(), file=sys.stderr)
|
||||
return
|
||||
return opt.last_operation
|
||||
|
||||
def add_postprocessing_to_metadata(opt,original_file,new_file,tool,command):
|
||||
original_file = original_file if os.path.exists(original_file) else os.path.join(opt.outdir,original_file)
|
||||
new_file = new_file if os.path.exists(new_file) else os.path.join(opt.outdir,new_file)
|
||||
meta = retrieve_metadata(original_file)['sd-metadata']
|
||||
img_data = meta['image']
|
||||
pp = img_data.get('postprocessing',[]) or []
|
||||
pp.append(
|
||||
{
|
||||
'tool':tool,
|
||||
'dream_command':command,
|
||||
}
|
||||
)
|
||||
meta['image']['postprocessing'] = pp
|
||||
write_metadata(new_file,meta)
|
||||
|
||||
def prepare_image_metadata(
|
||||
opt,
|
||||
prefix,
|
||||
seed,
|
||||
operation='generate',
|
||||
prior_variations=[],
|
||||
postprocessed=False,
|
||||
first_seed=None
|
||||
):
|
||||
|
||||
if postprocessed and opt.save_original:
|
||||
filename = choose_postprocess_name(opt,prefix,seed)
|
||||
else:
|
||||
filename = f'{prefix}.{seed}.png'
|
||||
|
||||
if opt.variation_amount > 0:
|
||||
first_seed = first_seed or seed
|
||||
this_variation = [[seed, opt.variation_amount]]
|
||||
opt.with_variations = prior_variations + this_variation
|
||||
formatted_dream_prompt = opt.dream_prompt_str(seed=first_seed)
|
||||
elif len(prior_variations) > 0:
|
||||
formatted_dream_prompt = opt.dream_prompt_str(seed=first_seed)
|
||||
elif operation == 'postprocess':
|
||||
formatted_dream_prompt = '!fix '+opt.dream_prompt_str(seed=seed)
|
||||
else:
|
||||
formatted_dream_prompt = opt.dream_prompt_str(seed=seed)
|
||||
return filename,formatted_dream_prompt
|
||||
|
||||
def choose_postprocess_name(opt,prefix,seed) -> str:
|
||||
match = re.search('postprocess:(\w+)',opt.last_operation)
|
||||
if match:
|
||||
modifier = match.group(1) # will look like "gfpgan", "upscale", "outpaint" or "embiggen"
|
||||
else:
|
||||
modifier = 'postprocessed'
|
||||
|
||||
counter = 0
|
||||
filename = None
|
||||
available = False
|
||||
while not available:
|
||||
if counter == 0:
|
||||
filename = f'{prefix}.{seed}.{modifier}.png'
|
||||
else:
|
||||
filename = f'{prefix}.{seed}.{modifier}-{counter:02d}.png'
|
||||
available = not os.path.exists(os.path.join(opt.outdir,filename))
|
||||
counter += 1
|
||||
return filename
|
||||
|
||||
def get_next_command(infile=None) -> str: # command string
|
||||
if infile is None:
|
||||
command = input('dream> ')
|
||||
else:
|
||||
command = infile.readline()
|
||||
if not command:
|
||||
raise EOFError
|
||||
else:
|
||||
command = command.strip()
|
||||
if len(command)>0:
|
||||
print(f'#{command}')
|
||||
return command
|
||||
|
||||
def invoke_ai_web_server_loop(gen, gfpgan, codeformer, esrgan):
|
||||
print('\n* --web was specified, starting web server...')
|
||||
# Change working directory to the stable-diffusion directory
|
||||
os.chdir(
|
||||
os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
|
||||
)
|
||||
|
||||
invoke_ai_web_server = InvokeAIWebServer(generate=gen, gfpgan=gfpgan, codeformer=codeformer, esrgan=esrgan)
|
||||
|
||||
try:
|
||||
invoke_ai_web_server.run()
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
|
||||
|
||||
def split_variations(variations_string) -> list:
|
||||
# shotgun parsing, woo
|
||||
parts = []
|
||||
broken = False # python doesn't have labeled loops...
|
||||
for part in variations_string.split(','):
|
||||
seed_and_weight = part.split(':')
|
||||
if len(seed_and_weight) != 2:
|
||||
print(f'** Could not parse with_variation part "{part}"')
|
||||
broken = True
|
||||
break
|
||||
try:
|
||||
seed = int(seed_and_weight[0])
|
||||
weight = float(seed_and_weight[1])
|
||||
except ValueError:
|
||||
print(f'** Could not parse with_variation part "{part}"')
|
||||
broken = True
|
||||
break
|
||||
parts.append([seed, weight])
|
||||
if broken:
|
||||
return None
|
||||
elif len(parts) == 0:
|
||||
return None
|
||||
else:
|
||||
return parts
|
||||
|
||||
def retrieve_dream_command(opt,file_path,completer):
|
||||
'''
|
||||
Given a full or partial path to a previously-generated image file,
|
||||
will retrieve and format the dream command used to generate the image,
|
||||
and pop it into the readline buffer (linux, Mac), or print out a comment
|
||||
for cut-and-paste (windows)
|
||||
'''
|
||||
dir,basename = os.path.split(file_path)
|
||||
if len(dir) == 0:
|
||||
path = os.path.join(opt.outdir,basename)
|
||||
else:
|
||||
path = file_path
|
||||
try:
|
||||
cmd = dream_cmd_from_png(path)
|
||||
except OSError:
|
||||
print(f'** {path}: file could not be read')
|
||||
return
|
||||
except (KeyError, AttributeError):
|
||||
print(f'** {path}: file has no metadata')
|
||||
return
|
||||
completer.set_line(cmd)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
@ -1,12 +1,12 @@
|
||||
#!/usr/bin/env python3
|
||||
'''This script reads the "Dream" Stable Diffusion prompt embedded in files generated by dream.py'''
|
||||
'''This script reads the "Invoke" Stable Diffusion prompt embedded in files generated by invoke.py'''
|
||||
|
||||
import sys
|
||||
from PIL import Image,PngImagePlugin
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: file2prompt.py <file1.png> <file2.png> <file3.png>...")
|
||||
print("This script opens up the indicated dream.py-generated PNG file(s) and prints out the prompt used to generate them.")
|
||||
print("This script opens up the indicated invoke.py-generated PNG file(s) and prints out the prompt used to generate them.")
|
||||
exit(-1)
|
||||
|
||||
filenames = sys.argv[1:]
|
||||
|
573
scripts/invoke.py
Normal file
@ -0,0 +1,573 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2022 Lincoln D. Stein (https://github.com/lstein)
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import shlex
|
||||
import copy
|
||||
import warnings
|
||||
import time
|
||||
import traceback
|
||||
sys.path.append('.') # corrects a weird problem on Macs
|
||||
from ldm.invoke.readline import get_completer
|
||||
from ldm.invoke.args import Args, metadata_dumps, metadata_from_png, dream_cmd_from_png
|
||||
from ldm.invoke.pngwriter import PngWriter, retrieve_metadata, write_metadata
|
||||
from ldm.invoke.image_util import make_grid
|
||||
from ldm.invoke.log import write_log
|
||||
from omegaconf import OmegaConf
|
||||
from backend.invoke_ai_web_server import InvokeAIWebServer
|
||||
|
||||
|
||||
def main():
|
||||
"""Initialize command-line parsers and the diffusion model"""
|
||||
opt = Args()
|
||||
args = opt.parse_args()
|
||||
if not args:
|
||||
sys.exit(-1)
|
||||
|
||||
if args.laion400m:
|
||||
print('--laion400m flag has been deprecated. Please use --model laion400m instead.')
|
||||
sys.exit(-1)
|
||||
if args.weights:
|
||||
print('--weights argument has been deprecated. Please edit ./configs/models.yaml, and select the weights using --model instead.')
|
||||
sys.exit(-1)
|
||||
|
||||
print('* Initializing, be patient...\n')
|
||||
from ldm.generate import Generate
|
||||
|
||||
# these two lines prevent a horrible warning message from appearing
|
||||
# when the frozen CLIP tokenizer is imported
|
||||
import transformers
|
||||
transformers.logging.set_verbosity_error()
|
||||
|
||||
# Loading Face Restoration and ESRGAN Modules
|
||||
try:
|
||||
gfpgan, codeformer, esrgan = None, None, None
|
||||
if opt.restore or opt.esrgan:
|
||||
from ldm.invoke.restoration import Restoration
|
||||
restoration = Restoration()
|
||||
if opt.restore:
|
||||
gfpgan, codeformer = restoration.load_face_restore_models(opt.gfpgan_dir, opt.gfpgan_model_path)
|
||||
else:
|
||||
print('>> Face restoration disabled')
|
||||
if opt.esrgan:
|
||||
esrgan = restoration.load_esrgan(opt.esrgan_bg_tile)
|
||||
else:
|
||||
print('>> Upscaling disabled')
|
||||
else:
|
||||
print('>> Face restoration and upscaling disabled')
|
||||
except (ModuleNotFoundError, ImportError):
|
||||
print(traceback.format_exc(), file=sys.stderr)
|
||||
print('>> You may need to install the ESRGAN and/or GFPGAN modules')
|
||||
|
||||
# creating a simple text2image object with a handful of
|
||||
# defaults passed on the command line.
|
||||
# additional parameters will be added (or overriden) during
|
||||
# the user input loop
|
||||
try:
|
||||
gen = Generate(
|
||||
conf = opt.conf,
|
||||
model = opt.model,
|
||||
sampler_name = opt.sampler_name,
|
||||
embedding_path = opt.embedding_path,
|
||||
full_precision = opt.full_precision,
|
||||
precision = opt.precision,
|
||||
gfpgan=gfpgan,
|
||||
codeformer=codeformer,
|
||||
esrgan=esrgan,
|
||||
free_gpu_mem=opt.free_gpu_mem,
|
||||
)
|
||||
except (FileNotFoundError, IOError, KeyError) as e:
|
||||
print(f'{e}. Aborting.')
|
||||
sys.exit(-1)
|
||||
|
||||
# make sure the output directory exists
|
||||
if not os.path.exists(opt.outdir):
|
||||
os.makedirs(opt.outdir)
|
||||
|
||||
# load the infile as a list of lines
|
||||
infile = None
|
||||
if opt.infile:
|
||||
try:
|
||||
if os.path.isfile(opt.infile):
|
||||
infile = open(opt.infile, 'r', encoding='utf-8')
|
||||
elif opt.infile == '-': # stdin
|
||||
infile = sys.stdin
|
||||
else:
|
||||
raise FileNotFoundError(f'{opt.infile} not found.')
|
||||
except (FileNotFoundError, IOError) as e:
|
||||
print(f'{e}. Aborting.')
|
||||
sys.exit(-1)
|
||||
|
||||
if opt.seamless:
|
||||
print(">> changed to seamless tiling mode")
|
||||
|
||||
# preload the model
|
||||
gen.load_model()
|
||||
|
||||
# web server loops forever
|
||||
if opt.web or opt.gui:
|
||||
invoke_ai_web_server_loop(gen, gfpgan, codeformer, esrgan)
|
||||
sys.exit(0)
|
||||
|
||||
if not infile:
|
||||
print(
|
||||
"\n* Initialization done! Awaiting your command (-h for help, 'q' to quit)"
|
||||
)
|
||||
|
||||
main_loop(gen, opt, infile)
|
||||
|
||||
# TODO: main_loop() has gotten busy. Needs to be refactored.
|
||||
def main_loop(gen, opt, infile):
|
||||
"""prompt/read/execute loop"""
|
||||
done = False
|
||||
path_filter = re.compile(r'[<>:"/\\|?*]')
|
||||
last_results = list()
|
||||
model_config = OmegaConf.load(opt.conf)[opt.model]
|
||||
|
||||
# The readline completer reads history from the .dream_history file located in the
|
||||
# output directory specified at the time of script launch. We do not currently support
|
||||
# changing the history file midstream when the output directory is changed.
|
||||
completer = get_completer(opt)
|
||||
output_cntr = completer.get_current_history_length()+1
|
||||
|
||||
# os.pathconf is not available on Windows
|
||||
if hasattr(os, 'pathconf'):
|
||||
path_max = os.pathconf(opt.outdir, 'PC_PATH_MAX')
|
||||
name_max = os.pathconf(opt.outdir, 'PC_NAME_MAX')
|
||||
else:
|
||||
path_max = 260
|
||||
name_max = 255
|
||||
|
||||
while not done:
|
||||
operation = 'generate' # default operation, alternative is 'postprocess'
|
||||
|
||||
if completer:
|
||||
completer.set_default_dir(opt.outdir)
|
||||
|
||||
try:
|
||||
command = get_next_command(infile)
|
||||
except EOFError:
|
||||
done = True
|
||||
continue
|
||||
|
||||
# skip empty lines
|
||||
if not command.strip():
|
||||
continue
|
||||
|
||||
if command.startswith(('#', '//')):
|
||||
continue
|
||||
|
||||
if len(command.strip()) == 1 and command.startswith('q'):
|
||||
done = True
|
||||
break
|
||||
|
||||
if command.startswith('!'):
|
||||
subcommand = command[1:]
|
||||
|
||||
if subcommand.startswith('dream'): # in case a stored prompt still contains the !dream command
|
||||
command = command.replace('!dream ','',1)
|
||||
|
||||
elif subcommand.startswith('fix'):
|
||||
command = command.replace('!fix ','',1)
|
||||
operation = 'postprocess'
|
||||
|
||||
elif subcommand.startswith('fetch'):
|
||||
file_path = command.replace('!fetch ','',1)
|
||||
retrieve_dream_command(opt,file_path,completer)
|
||||
continue
|
||||
|
||||
elif subcommand.startswith('history'):
|
||||
completer.show_history()
|
||||
continue
|
||||
|
||||
elif subcommand.startswith('search'):
|
||||
search_str = command.replace('!search ','',1)
|
||||
completer.show_history(search_str)
|
||||
continue
|
||||
|
||||
elif subcommand.startswith('clear'):
|
||||
completer.clear_history()
|
||||
continue
|
||||
|
||||
elif re.match('^(\d+)',subcommand):
|
||||
command_no = re.match('^(\d+)',subcommand).groups()[0]
|
||||
command = completer.get_line(int(command_no))
|
||||
completer.set_line(command)
|
||||
continue
|
||||
|
||||
else: # not a recognized subcommand, so give the --help text
|
||||
command = '-h'
|
||||
|
||||
if opt.parse_cmd(command) is None:
|
||||
continue
|
||||
|
||||
if opt.init_img:
|
||||
try:
|
||||
if not opt.prompt:
|
||||
oldargs = metadata_from_png(opt.init_img)
|
||||
opt.prompt = oldargs.prompt
|
||||
print(f'>> Retrieved old prompt "{opt.prompt}" from {opt.init_img}')
|
||||
except (OSError, AttributeError, KeyError):
|
||||
pass
|
||||
|
||||
if len(opt.prompt) == 0:
|
||||
print('\nTry again with a prompt!')
|
||||
continue
|
||||
|
||||
# width and height are set by model if not specified
|
||||
if not opt.width:
|
||||
opt.width = model_config.width
|
||||
if not opt.height:
|
||||
opt.height = model_config.height
|
||||
|
||||
# retrieve previous value of init image if requested
|
||||
if opt.init_img is not None and re.match('^-\\d+$', opt.init_img):
|
||||
try:
|
||||
opt.init_img = last_results[int(opt.init_img)][0]
|
||||
print(f'>> Reusing previous image {opt.init_img}')
|
||||
except IndexError:
|
||||
print(
|
||||
f'>> No previous initial image at position {opt.init_img} found')
|
||||
opt.init_img = None
|
||||
continue
|
||||
|
||||
# try to relativize pathnames
|
||||
for attr in ('init_img','init_mask','init_color','embedding_path'):
|
||||
if getattr(opt,attr) and not os.path.exists(getattr(opt,attr)):
|
||||
basename = getattr(opt,attr)
|
||||
path = os.path.join(opt.outdir,basename)
|
||||
setattr(opt,attr,path)
|
||||
|
||||
# retrieve previous value of seed if requested
|
||||
if opt.seed is not None and opt.seed < 0:
|
||||
try:
|
||||
opt.seed = last_results[opt.seed][1]
|
||||
print(f'>> Reusing previous seed {opt.seed}')
|
||||
except IndexError:
|
||||
print(f'>> No previous seed at position {opt.seed} found')
|
||||
opt.seed = None
|
||||
continue
|
||||
|
||||
if opt.strength is None:
|
||||
opt.strength = 0.75 if opt.out_direction is None else 0.83
|
||||
|
||||
if opt.with_variations is not None:
|
||||
opt.with_variations = split_variations(opt.with_variations)
|
||||
|
||||
if opt.prompt_as_dir and operation == 'generate':
|
||||
# sanitize the prompt to a valid folder name
|
||||
subdir = path_filter.sub('_', opt.prompt)[:name_max].rstrip(' .')
|
||||
|
||||
# truncate path to maximum allowed length
|
||||
# 39 is the length of '######.##########.##########-##.png', plus two separators and a NUL
|
||||
subdir = subdir[:(path_max - 39 - len(os.path.abspath(opt.outdir)))]
|
||||
current_outdir = os.path.join(opt.outdir, subdir)
|
||||
|
||||
print('Writing files to directory: "' + current_outdir + '"')
|
||||
|
||||
# make sure the output directory exists
|
||||
if not os.path.exists(current_outdir):
|
||||
os.makedirs(current_outdir)
|
||||
else:
|
||||
if not os.path.exists(opt.outdir):
|
||||
os.makedirs(opt.outdir)
|
||||
current_outdir = opt.outdir
|
||||
|
||||
# write out the history at this point
|
||||
if operation == 'postprocess':
|
||||
completer.add_history(f'!fix {command}')
|
||||
else:
|
||||
completer.add_history(command)
|
||||
|
||||
# Here is where the images are actually generated!
|
||||
last_results = []
|
||||
try:
|
||||
file_writer = PngWriter(current_outdir)
|
||||
results = [] # list of filename, prompt pairs
|
||||
grid_images = dict() # seed -> Image, only used if `opt.grid`
|
||||
prior_variations = opt.with_variations or []
|
||||
prefix = file_writer.unique_prefix()
|
||||
|
||||
def image_writer(image, seed, upscaled=False, first_seed=None, use_prefix=None):
|
||||
# note the seed is the seed of the current image
|
||||
# the first_seed is the original seed that noise is added to
|
||||
# when the -v switch is used to generate variations
|
||||
nonlocal prior_variations
|
||||
nonlocal prefix
|
||||
if use_prefix is not None:
|
||||
prefix = use_prefix
|
||||
|
||||
path = None
|
||||
if opt.grid:
|
||||
grid_images[seed] = image
|
||||
else:
|
||||
postprocessed = upscaled if upscaled else operation=='postprocess'
|
||||
filename, formatted_dream_prompt = prepare_image_metadata(
|
||||
opt,
|
||||
prefix,
|
||||
seed,
|
||||
operation,
|
||||
prior_variations,
|
||||
postprocessed,
|
||||
first_seed
|
||||
)
|
||||
path = file_writer.save_image_and_prompt_to_png(
|
||||
image = image,
|
||||
dream_prompt = formatted_dream_prompt,
|
||||
metadata = metadata_dumps(
|
||||
opt,
|
||||
seeds = [seed if opt.variation_amount==0 and len(prior_variations)==0 else first_seed],
|
||||
model_hash = gen.model_hash,
|
||||
),
|
||||
name = filename,
|
||||
)
|
||||
|
||||
# update rfc metadata
|
||||
if operation == 'postprocess':
|
||||
tool = re.match('postprocess:(\w+)',opt.last_operation).groups()[0]
|
||||
add_postprocessing_to_metadata(
|
||||
opt,
|
||||
opt.prompt,
|
||||
filename,
|
||||
tool,
|
||||
formatted_dream_prompt,
|
||||
)
|
||||
|
||||
if (not postprocessed) or opt.save_original:
|
||||
# only append to results if we didn't overwrite an earlier output
|
||||
results.append([path, formatted_dream_prompt])
|
||||
|
||||
# so that the seed autocompletes (on linux|mac when -S or --seed specified
|
||||
if completer:
|
||||
completer.add_seed(seed)
|
||||
completer.add_seed(first_seed)
|
||||
last_results.append([path, seed])
|
||||
|
||||
if operation == 'generate':
|
||||
catch_ctrl_c = infile is None # if running interactively, we catch keyboard interrupts
|
||||
opt.last_operation='generate'
|
||||
gen.prompt2image(
|
||||
image_callback=image_writer,
|
||||
catch_interrupts=catch_ctrl_c,
|
||||
**vars(opt)
|
||||
)
|
||||
elif operation == 'postprocess':
|
||||
print(f'>> fixing {opt.prompt}')
|
||||
opt.last_operation = do_postprocess(gen,opt,image_writer)
|
||||
|
||||
if opt.grid and len(grid_images) > 0:
|
||||
grid_img = make_grid(list(grid_images.values()))
|
||||
grid_seeds = list(grid_images.keys())
|
||||
first_seed = last_results[0][1]
|
||||
filename = f'{prefix}.{first_seed}.png'
|
||||
formatted_dream_prompt = opt.dream_prompt_str(seed=first_seed,grid=True,iterations=len(grid_images))
|
||||
formatted_dream_prompt += f' # {grid_seeds}'
|
||||
metadata = metadata_dumps(
|
||||
opt,
|
||||
seeds = grid_seeds,
|
||||
model_hash = gen.model_hash
|
||||
)
|
||||
path = file_writer.save_image_and_prompt_to_png(
|
||||
image = grid_img,
|
||||
dream_prompt = formatted_dream_prompt,
|
||||
metadata = metadata,
|
||||
name = filename
|
||||
)
|
||||
results = [[path, formatted_dream_prompt]]
|
||||
|
||||
except AssertionError as e:
|
||||
print(e)
|
||||
continue
|
||||
|
||||
except OSError as e:
|
||||
print(e)
|
||||
continue
|
||||
|
||||
print('Outputs:')
|
||||
log_path = os.path.join(current_outdir, 'invoke_log')
|
||||
output_cntr = write_log(results, log_path ,('txt', 'md'), output_cntr)
|
||||
print()
|
||||
|
||||
print('goodbye!')
|
||||
|
||||
def do_postprocess (gen, opt, callback):
|
||||
file_path = opt.prompt # treat the prompt as the file pathname
|
||||
if os.path.dirname(file_path) == '': #basename given
|
||||
file_path = os.path.join(opt.outdir,file_path)
|
||||
|
||||
tool=None
|
||||
if opt.gfpgan_strength > 0:
|
||||
tool = opt.facetool
|
||||
elif opt.embiggen:
|
||||
tool = 'embiggen'
|
||||
elif opt.upscale:
|
||||
tool = 'upscale'
|
||||
elif opt.out_direction:
|
||||
tool = 'outpaint'
|
||||
elif opt.outcrop:
|
||||
tool = 'outcrop'
|
||||
opt.save_original = True # do not overwrite old image!
|
||||
opt.last_operation = f'postprocess:{tool}'
|
||||
try:
|
||||
gen.apply_postprocessor(
|
||||
image_path = file_path,
|
||||
tool = tool,
|
||||
gfpgan_strength = opt.gfpgan_strength,
|
||||
codeformer_fidelity = opt.codeformer_fidelity,
|
||||
save_original = opt.save_original,
|
||||
upscale = opt.upscale,
|
||||
out_direction = opt.out_direction,
|
||||
outcrop = opt.outcrop,
|
||||
callback = callback,
|
||||
opt = opt,
|
||||
)
|
||||
except OSError:
|
||||
print(traceback.format_exc(), file=sys.stderr)
|
||||
print(f'** {file_path}: file could not be read')
|
||||
return
|
||||
except (KeyError, AttributeError):
|
||||
print(traceback.format_exc(), file=sys.stderr)
|
||||
return
|
||||
return opt.last_operation
|
||||
|
||||
def add_postprocessing_to_metadata(opt,original_file,new_file,tool,command):
|
||||
original_file = original_file if os.path.exists(original_file) else os.path.join(opt.outdir,original_file)
|
||||
new_file = new_file if os.path.exists(new_file) else os.path.join(opt.outdir,new_file)
|
||||
meta = retrieve_metadata(original_file)['sd-metadata']
|
||||
img_data = meta['image']
|
||||
pp = img_data.get('postprocessing',[]) or []
|
||||
pp.append(
|
||||
{
|
||||
'tool':tool,
|
||||
'dream_command':command,
|
||||
}
|
||||
)
|
||||
meta['image']['postprocessing'] = pp
|
||||
write_metadata(new_file,meta)
|
||||
|
||||
def prepare_image_metadata(
|
||||
opt,
|
||||
prefix,
|
||||
seed,
|
||||
operation='generate',
|
||||
prior_variations=[],
|
||||
postprocessed=False,
|
||||
first_seed=None
|
||||
):
|
||||
|
||||
if postprocessed and opt.save_original:
|
||||
filename = choose_postprocess_name(opt,prefix,seed)
|
||||
else:
|
||||
filename = f'{prefix}.{seed}.png'
|
||||
|
||||
if opt.variation_amount > 0:
|
||||
first_seed = first_seed or seed
|
||||
this_variation = [[seed, opt.variation_amount]]
|
||||
opt.with_variations = prior_variations + this_variation
|
||||
formatted_dream_prompt = opt.dream_prompt_str(seed=first_seed)
|
||||
elif len(prior_variations) > 0:
|
||||
formatted_dream_prompt = opt.dream_prompt_str(seed=first_seed)
|
||||
elif operation == 'postprocess':
|
||||
formatted_dream_prompt = '!fix '+opt.dream_prompt_str(seed=seed)
|
||||
else:
|
||||
formatted_dream_prompt = opt.dream_prompt_str(seed=seed)
|
||||
return filename,formatted_dream_prompt
|
||||
|
||||
def choose_postprocess_name(opt,prefix,seed) -> str:
|
||||
match = re.search('postprocess:(\w+)',opt.last_operation)
|
||||
if match:
|
||||
modifier = match.group(1) # will look like "gfpgan", "upscale", "outpaint" or "embiggen"
|
||||
else:
|
||||
modifier = 'postprocessed'
|
||||
|
||||
counter = 0
|
||||
filename = None
|
||||
available = False
|
||||
while not available:
|
||||
if counter == 0:
|
||||
filename = f'{prefix}.{seed}.{modifier}.png'
|
||||
else:
|
||||
filename = f'{prefix}.{seed}.{modifier}-{counter:02d}.png'
|
||||
available = not os.path.exists(os.path.join(opt.outdir,filename))
|
||||
counter += 1
|
||||
return filename
|
||||
|
||||
def get_next_command(infile=None) -> str: # command string
|
||||
if infile is None:
|
||||
command = input('invoke> ')
|
||||
else:
|
||||
command = infile.readline()
|
||||
if not command:
|
||||
raise EOFError
|
||||
else:
|
||||
command = command.strip()
|
||||
if len(command)>0:
|
||||
print(f'#{command}')
|
||||
return command
|
||||
|
||||
def invoke_ai_web_server_loop(gen, gfpgan, codeformer, esrgan):
|
||||
print('\n* --web was specified, starting web server...')
|
||||
# Change working directory to the stable-diffusion directory
|
||||
os.chdir(
|
||||
os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
|
||||
)
|
||||
|
||||
invoke_ai_web_server = InvokeAIWebServer(generate=gen, gfpgan=gfpgan, codeformer=codeformer, esrgan=esrgan)
|
||||
|
||||
try:
|
||||
invoke_ai_web_server.run()
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
|
||||
|
||||
def split_variations(variations_string) -> list:
|
||||
# shotgun parsing, woo
|
||||
parts = []
|
||||
broken = False # python doesn't have labeled loops...
|
||||
for part in variations_string.split(','):
|
||||
seed_and_weight = part.split(':')
|
||||
if len(seed_and_weight) != 2:
|
||||
print(f'** Could not parse with_variation part "{part}"')
|
||||
broken = True
|
||||
break
|
||||
try:
|
||||
seed = int(seed_and_weight[0])
|
||||
weight = float(seed_and_weight[1])
|
||||
except ValueError:
|
||||
print(f'** Could not parse with_variation part "{part}"')
|
||||
broken = True
|
||||
break
|
||||
parts.append([seed, weight])
|
||||
if broken:
|
||||
return None
|
||||
elif len(parts) == 0:
|
||||
return None
|
||||
else:
|
||||
return parts
|
||||
|
||||
def retrieve_dream_command(opt,file_path,completer):
|
||||
'''
|
||||
Given a full or partial path to a previously-generated image file,
|
||||
will retrieve and format the dream command used to generate the image,
|
||||
and pop it into the readline buffer (linux, Mac), or print out a comment
|
||||
for cut-and-paste (windows)
|
||||
'''
|
||||
dir,basename = os.path.split(file_path)
|
||||
if len(dir) == 0:
|
||||
path = os.path.join(opt.outdir,basename)
|
||||
else:
|
||||
path = file_path
|
||||
try:
|
||||
cmd = dream_cmd_from_png(path)
|
||||
except OSError:
|
||||
print(f'** {path}: file could not be read')
|
||||
return
|
||||
except (KeyError, AttributeError):
|
||||
print(f'** {path}: file has no metadata')
|
||||
return
|
||||
completer.set_line(cmd)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
@ -18,7 +18,7 @@ from pytorch_lightning import seed_everything
|
||||
from ldm.util import instantiate_from_config
|
||||
from ldm.models.diffusion.ddim import DDIMSampler
|
||||
from ldm.models.diffusion.plms import PLMSSampler
|
||||
from ldm.dream.devices import choose_torch_device
|
||||
from ldm.invoke.devices import choose_torch_device
|
||||
|
||||
|
||||
def chunk(it, size):
|
||||
|
@ -6,7 +6,7 @@ import numpy as np
|
||||
import torch
|
||||
from main import instantiate_from_config
|
||||
from ldm.models.diffusion.ddim import DDIMSampler
|
||||
from ldm.dream.devices import choose_torch_device
|
||||
from ldm.invoke.devices import choose_torch_device
|
||||
|
||||
def make_batch(image, mask, device):
|
||||
image = np.array(Image.open(image).convert("RGB"))
|
||||
|
@ -18,7 +18,7 @@ import torch.nn as nn
|
||||
from ldm.util import instantiate_from_config
|
||||
from ldm.models.diffusion.ddim import DDIMSampler
|
||||
from ldm.models.diffusion.plms import PLMSSampler
|
||||
from ldm.dream.devices import choose_torch_device
|
||||
from ldm.invoke.devices import choose_torch_device
|
||||
|
||||
def chunk(it, size):
|
||||
it = iter(it)
|
||||
|
@ -15,13 +15,13 @@ import urllib.request
|
||||
transformers.logging.set_verbosity_error()
|
||||
|
||||
# this will preload the Bert tokenizer fles
|
||||
print('preloading bert tokenizer...')
|
||||
print('preloading bert tokenizer...', end='')
|
||||
|
||||
tokenizer = BertTokenizerFast.from_pretrained('bert-base-uncased')
|
||||
print('...success')
|
||||
|
||||
# this will download requirements for Kornia
|
||||
print('preloading Kornia requirements (ignore the deprecation warnings)...')
|
||||
print('preloading Kornia requirements...', end='')
|
||||
with warnings.catch_warnings():
|
||||
warnings.filterwarnings('ignore', category=DeprecationWarning)
|
||||
import kornia
|
||||
@ -29,12 +29,12 @@ print('...success')
|
||||
|
||||
version = 'openai/clip-vit-large-patch14'
|
||||
|
||||
print('preloading CLIP model (Ignore the deprecation warnings)...')
|
||||
print('preloading CLIP model...',end='')
|
||||
sys.stdout.flush()
|
||||
|
||||
tokenizer = CLIPTokenizer.from_pretrained(version)
|
||||
transformer = CLIPTextModel.from_pretrained(version)
|
||||
print('\n\n...success')
|
||||
print('...success')
|
||||
|
||||
# In the event that the user has installed GFPGAN and also elected to use
|
||||
# RealESRGAN, this will attempt to download the model needed by RealESRGANer
|
||||
@ -47,7 +47,7 @@ except ModuleNotFoundError:
|
||||
pass
|
||||
|
||||
if gfpgan:
|
||||
print('Loading models from RealESRGAN and facexlib')
|
||||
print('Loading models from RealESRGAN and facexlib...',end='')
|
||||
try:
|
||||
from realesrgan.archs.srvgg_arch import SRVGGNetCompact
|
||||
from facexlib.utils.face_restoration_helper import FaceRestoreHelper
|
||||
@ -65,27 +65,41 @@ if gfpgan:
|
||||
print('Error loading ESRGAN:')
|
||||
print(traceback.format_exc())
|
||||
|
||||
try:
|
||||
import urllib.request
|
||||
model_url = 'https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.4.pth'
|
||||
model_dest = 'src/gfpgan/experiments/pretrained_models/GFPGANv1.4.pth'
|
||||
print('Loading models from GFPGAN')
|
||||
import urllib.request
|
||||
for model in (
|
||||
[
|
||||
'https://github.com/TencentARC/GFPGAN/releases/download/v1.3.0/GFPGANv1.4.pth',
|
||||
'src/gfpgan/experiments/pretrained_models/GFPGANv1.4.pth'
|
||||
],
|
||||
[
|
||||
'https://github.com/xinntao/facexlib/releases/download/v0.1.0/detection_Resnet50_Final.pth',
|
||||
'./gfpgan/weights/detection_Resnet50_Final.pth'
|
||||
],
|
||||
[
|
||||
'https://github.com/xinntao/facexlib/releases/download/v0.2.2/parsing_parsenet.pth',
|
||||
'./gfpgan/weights/parsing_parsenet.pth'
|
||||
],
|
||||
):
|
||||
model_url,model_dest = model
|
||||
try:
|
||||
if not os.path.exists(model_dest):
|
||||
print(f'Downloading gfpgan model file {model_url}...',end='')
|
||||
os.makedirs(os.path.dirname(model_dest), exist_ok=True)
|
||||
urllib.request.urlretrieve(model_url,model_dest)
|
||||
print('...success')
|
||||
except Exception:
|
||||
import traceback
|
||||
print('Error loading GFPGAN:')
|
||||
print(traceback.format_exc())
|
||||
|
||||
if not os.path.exists(model_dest):
|
||||
print('downloading gfpgan model file...')
|
||||
urllib.request.urlretrieve(model_url,model_dest)
|
||||
except Exception:
|
||||
import traceback
|
||||
print('Error loading GFPGAN:')
|
||||
print(traceback.format_exc())
|
||||
print('...success')
|
||||
|
||||
print('preloading CodeFormer model file...')
|
||||
print('preloading CodeFormer model file...',end='')
|
||||
try:
|
||||
import urllib.request
|
||||
model_url = 'https://github.com/sczhou/CodeFormer/releases/download/v0.1.0/codeformer.pth'
|
||||
model_dest = 'ldm/dream/restoration/codeformer/weights/codeformer.pth'
|
||||
model_dest = 'ldm/invoke/restoration/codeformer/weights/codeformer.pth'
|
||||
if not os.path.exists(model_dest):
|
||||
print('downloading codeformer model file...')
|
||||
print('Downloading codeformer model file...')
|
||||
os.makedirs(os.path.dirname(model_dest), exist_ok=True)
|
||||
urllib.request.urlretrieve(model_url,model_dest)
|
||||
except Exception:
|
||||
|
@ -2,11 +2,11 @@
|
||||
|
||||
import sys
|
||||
import json
|
||||
from ldm.dream.pngwriter import retrieve_metadata
|
||||
from ldm.invoke.pngwriter import retrieve_metadata
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: file2prompt.py <file1.png> <file2.png> <file3.png>...")
|
||||
print("This script opens up the indicated dream.py-generated PNG file(s) and prints out their metadata.")
|
||||
print("This script opens up the indicated invoke.py-generated PNG file(s) and prints out their metadata.")
|
||||
exit(-1)
|
||||
|
||||
filenames = sys.argv[1:]
|
||||
|
@ -10,7 +10,7 @@ from flask_cors import CORS
|
||||
from flask_socketio import SocketIO
|
||||
from omegaconf import OmegaConf
|
||||
from dependency_injector.wiring import inject, Provide
|
||||
from ldm.dream.args import Args
|
||||
from ldm.invoke.args import Args
|
||||
from server import views
|
||||
from server.containers import Container
|
||||
from server.services import GeneratorService, SignalService
|
||||
|
@ -12,12 +12,12 @@ import shlex
|
||||
from threading import Thread
|
||||
import time
|
||||
from flask_socketio import SocketIO, join_room, leave_room
|
||||
from ldm.dream.args import Args
|
||||
from ldm.dream.generator import embiggen
|
||||
from ldm.invoke.args import Args
|
||||
from ldm.invoke.generator import embiggen
|
||||
from PIL import Image
|
||||
|
||||
from ldm.dream.pngwriter import PngWriter
|
||||
from ldm.dream.server import CanceledException
|
||||
from ldm.invoke.pngwriter import PngWriter
|
||||
from ldm.invoke.server import CanceledException
|
||||
from ldm.generate import Generate
|
||||
from server.models import DreamResult, JobRequest, PaginatedItems, ProgressType, Signal
|
||||
|
||||
|