Spaces:
Runtime error
Runtime error
NN
commited on
Commit
·
b0b44df
1
Parent(s):
f5aa56d
Upload 144 files
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- stable-diffusion-webui-master/.github/ISSUE_TEMPLATE/bug_report.yml +83 -0
- stable-diffusion-webui-master/.github/ISSUE_TEMPLATE/config.yml +5 -0
- stable-diffusion-webui-master/.github/ISSUE_TEMPLATE/feature_request.yml +40 -0
- stable-diffusion-webui-master/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +28 -0
- stable-diffusion-webui-master/.github/workflows/on_pull_request.yaml +42 -0
- stable-diffusion-webui-master/.github/workflows/run_tests.yaml +31 -0
- stable-diffusion-webui-master/.gitignore +34 -0
- stable-diffusion-webui-master/.pylintrc +3 -0
- stable-diffusion-webui-master/CODEOWNERS +12 -0
- stable-diffusion-webui-master/README.md +150 -0
- stable-diffusion-webui-master/artists.csv +0 -0
- stable-diffusion-webui-master/embeddings/Place Textual Inversion embeddings here.txt +0 -0
- stable-diffusion-webui-master/environment-wsl2.yaml +11 -0
- stable-diffusion-webui-master/extensions/put extensions here.txt +0 -0
- stable-diffusion-webui-master/javascript/aspectRatioOverlay.js +108 -0
- stable-diffusion-webui-master/javascript/contextMenus.js +177 -0
- stable-diffusion-webui-master/javascript/dragdrop.js +89 -0
- stable-diffusion-webui-master/javascript/edit-attention.js +75 -0
- stable-diffusion-webui-master/javascript/extensions.js +35 -0
- stable-diffusion-webui-master/javascript/generationParams.js +33 -0
- stable-diffusion-webui-master/javascript/hints.js +129 -0
- stable-diffusion-webui-master/javascript/imageMaskFix.js +45 -0
- stable-diffusion-webui-master/javascript/imageParams.js +19 -0
- stable-diffusion-webui-master/javascript/imageviewer.js +276 -0
- stable-diffusion-webui-master/javascript/localization.js +167 -0
- stable-diffusion-webui-master/javascript/notification.js +49 -0
- stable-diffusion-webui-master/javascript/progressbar.js +137 -0
- stable-diffusion-webui-master/javascript/textualInversion.js +8 -0
- stable-diffusion-webui-master/javascript/ui.js +213 -0
- stable-diffusion-webui-master/launch.py +294 -0
- stable-diffusion-webui-master/localizations/Put localization files here.txt +0 -0
- stable-diffusion-webui-master/models/Stable-diffusion/Put Stable Diffusion checkpoints here.txt +0 -0
- stable-diffusion-webui-master/models/VAE/Put VAE here.txt +0 -0
- stable-diffusion-webui-master/models/deepbooru/Put your deepbooru release project folder here.txt +0 -0
- stable-diffusion-webui-master/modules/api/api.py +329 -0
- stable-diffusion-webui-master/modules/api/models.py +242 -0
- stable-diffusion-webui-master/modules/artists.py +25 -0
- stable-diffusion-webui-master/modules/call_queue.py +98 -0
- stable-diffusion-webui-master/modules/codeformer/codeformer_arch.py +278 -0
- stable-diffusion-webui-master/modules/codeformer/vqgan_arch.py +437 -0
- stable-diffusion-webui-master/modules/codeformer_model.py +143 -0
- stable-diffusion-webui-master/modules/deepbooru.py +97 -0
- stable-diffusion-webui-master/modules/deepbooru_model.py +676 -0
- stable-diffusion-webui-master/modules/devices.py +124 -0
- stable-diffusion-webui-master/modules/errors.py +10 -0
- stable-diffusion-webui-master/modules/esrgan_model.py +233 -0
- stable-diffusion-webui-master/modules/esrgan_model_arch.py +463 -0
- stable-diffusion-webui-master/modules/extensions.py +89 -0
- stable-diffusion-webui-master/modules/extras.py +313 -0
- stable-diffusion-webui-master/modules/face_restoration.py +19 -0
stable-diffusion-webui-master/.github/ISSUE_TEMPLATE/bug_report.yml
ADDED
@@ -0,0 +1,83 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: Bug Report
|
2 |
+
description: You think somethings is broken in the UI
|
3 |
+
title: "[Bug]: "
|
4 |
+
labels: ["bug-report"]
|
5 |
+
|
6 |
+
body:
|
7 |
+
- type: checkboxes
|
8 |
+
attributes:
|
9 |
+
label: Is there an existing issue for this?
|
10 |
+
description: Please search to see if an issue already exists for the bug you encountered, and that it hasn't been fixed in a recent build/commit.
|
11 |
+
options:
|
12 |
+
- label: I have searched the existing issues and checked the recent builds/commits
|
13 |
+
required: true
|
14 |
+
- type: markdown
|
15 |
+
attributes:
|
16 |
+
value: |
|
17 |
+
*Please fill this form with as much information as possible, don't forget to fill "What OS..." and "What browsers" and *provide screenshots if possible**
|
18 |
+
- type: textarea
|
19 |
+
id: what-did
|
20 |
+
attributes:
|
21 |
+
label: What happened?
|
22 |
+
description: Tell us what happened in a very clear and simple way
|
23 |
+
validations:
|
24 |
+
required: true
|
25 |
+
- type: textarea
|
26 |
+
id: steps
|
27 |
+
attributes:
|
28 |
+
label: Steps to reproduce the problem
|
29 |
+
description: Please provide us with precise step by step information on how to reproduce the bug
|
30 |
+
value: |
|
31 |
+
1. Go to ....
|
32 |
+
2. Press ....
|
33 |
+
3. ...
|
34 |
+
validations:
|
35 |
+
required: true
|
36 |
+
- type: textarea
|
37 |
+
id: what-should
|
38 |
+
attributes:
|
39 |
+
label: What should have happened?
|
40 |
+
description: tell what you think the normal behavior should be
|
41 |
+
validations:
|
42 |
+
required: true
|
43 |
+
- type: input
|
44 |
+
id: commit
|
45 |
+
attributes:
|
46 |
+
label: Commit where the problem happens
|
47 |
+
description: Which commit are you running ? (Do not write *Latest version/repo/commit*, as this means nothing and will have changed by the time we read your issue. Rather, copy the **Commit hash** shown in the cmd/terminal when you launch the UI)
|
48 |
+
validations:
|
49 |
+
required: true
|
50 |
+
- type: dropdown
|
51 |
+
id: platforms
|
52 |
+
attributes:
|
53 |
+
label: What platforms do you use to access UI ?
|
54 |
+
multiple: true
|
55 |
+
options:
|
56 |
+
- Windows
|
57 |
+
- Linux
|
58 |
+
- MacOS
|
59 |
+
- iOS
|
60 |
+
- Android
|
61 |
+
- Other/Cloud
|
62 |
+
- type: dropdown
|
63 |
+
id: browsers
|
64 |
+
attributes:
|
65 |
+
label: What browsers do you use to access the UI ?
|
66 |
+
multiple: true
|
67 |
+
options:
|
68 |
+
- Mozilla Firefox
|
69 |
+
- Google Chrome
|
70 |
+
- Brave
|
71 |
+
- Apple Safari
|
72 |
+
- Microsoft Edge
|
73 |
+
- type: textarea
|
74 |
+
id: cmdargs
|
75 |
+
attributes:
|
76 |
+
label: Command Line Arguments
|
77 |
+
description: Are you using any launching parameters/command line arguments (modified webui-user.py) ? If yes, please write them below
|
78 |
+
render: Shell
|
79 |
+
- type: textarea
|
80 |
+
id: misc
|
81 |
+
attributes:
|
82 |
+
label: Additional information, context and logs
|
83 |
+
description: Please provide us with any relevant additional info, context or log output.
|
stable-diffusion-webui-master/.github/ISSUE_TEMPLATE/config.yml
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
blank_issues_enabled: false
|
2 |
+
contact_links:
|
3 |
+
- name: WebUI Community Support
|
4 |
+
url: https://github.com/AUTOMATIC1111/stable-diffusion-webui/discussions
|
5 |
+
about: Please ask and answer questions here.
|
stable-diffusion-webui-master/.github/ISSUE_TEMPLATE/feature_request.yml
ADDED
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: Feature request
|
2 |
+
description: Suggest an idea for this project
|
3 |
+
title: "[Feature Request]: "
|
4 |
+
labels: ["suggestion"]
|
5 |
+
|
6 |
+
body:
|
7 |
+
- type: checkboxes
|
8 |
+
attributes:
|
9 |
+
label: Is there an existing issue for this?
|
10 |
+
description: Please search to see if an issue already exists for the feature you want, and that it's not implemented in a recent build/commit.
|
11 |
+
options:
|
12 |
+
- label: I have searched the existing issues and checked the recent builds/commits
|
13 |
+
required: true
|
14 |
+
- type: markdown
|
15 |
+
attributes:
|
16 |
+
value: |
|
17 |
+
*Please fill this form with as much information as possible, provide screenshots and/or illustrations of the feature if possible*
|
18 |
+
- type: textarea
|
19 |
+
id: feature
|
20 |
+
attributes:
|
21 |
+
label: What would your feature do ?
|
22 |
+
description: Tell us about your feature in a very clear and simple way, and what problem it would solve
|
23 |
+
validations:
|
24 |
+
required: true
|
25 |
+
- type: textarea
|
26 |
+
id: workflow
|
27 |
+
attributes:
|
28 |
+
label: Proposed workflow
|
29 |
+
description: Please provide us with step by step information on how you'd like the feature to be accessed and used
|
30 |
+
value: |
|
31 |
+
1. Go to ....
|
32 |
+
2. Press ....
|
33 |
+
3. ...
|
34 |
+
validations:
|
35 |
+
required: true
|
36 |
+
- type: textarea
|
37 |
+
id: misc
|
38 |
+
attributes:
|
39 |
+
label: Additional information
|
40 |
+
description: Add any other context or screenshots about the feature request here.
|
stable-diffusion-webui-master/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Please read the [contributing wiki page](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Contributing) before submitting a pull request!
|
2 |
+
|
3 |
+
If you have a large change, pay special attention to this paragraph:
|
4 |
+
|
5 |
+
> Before making changes, if you think that your feature will result in more than 100 lines changing, find me and talk to me about the feature you are proposing. It pains me to reject the hard work someone else did, but I won't add everything to the repo, and it's better if the rejection happens before you have to waste time working on the feature.
|
6 |
+
|
7 |
+
Otherwise, after making sure you're following the rules described in wiki page, remove this section and continue on.
|
8 |
+
|
9 |
+
**Describe what this pull request is trying to achieve.**
|
10 |
+
|
11 |
+
A clear and concise description of what you're trying to accomplish with this, so your intent doesn't have to be extracted from your code.
|
12 |
+
|
13 |
+
**Additional notes and description of your changes**
|
14 |
+
|
15 |
+
More technical discussion about your changes go here, plus anything that a maintainer might have to specifically take a look at, or be wary of.
|
16 |
+
|
17 |
+
**Environment this was tested in**
|
18 |
+
|
19 |
+
List the environment you have developed / tested this on. As per the contributing page, changes should be able to work on Windows out of the box.
|
20 |
+
- OS: [e.g. Windows, Linux]
|
21 |
+
- Browser [e.g. chrome, safari]
|
22 |
+
- Graphics card [e.g. NVIDIA RTX 2080 8GB, AMD RX 6600 8GB]
|
23 |
+
|
24 |
+
**Screenshots or videos of your changes**
|
25 |
+
|
26 |
+
If applicable, screenshots or a video showing off your changes. If it edits an existing UI, it should ideally contain a comparison of what used to be there, before your changes were made.
|
27 |
+
|
28 |
+
This is **required** for anything that touches the user interface.
|
stable-diffusion-webui-master/.github/workflows/on_pull_request.yaml
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# See https://github.com/actions/starter-workflows/blob/1067f16ad8a1eac328834e4b0ae24f7d206f810d/ci/pylint.yml for original reference file
|
2 |
+
name: Run Linting/Formatting on Pull Requests
|
3 |
+
|
4 |
+
on:
|
5 |
+
- push
|
6 |
+
- pull_request
|
7 |
+
# See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#onpull_requestpull_request_targetbranchesbranches-ignore for syntax docs
|
8 |
+
# if you want to filter out branches, delete the `- pull_request` and uncomment these lines :
|
9 |
+
# pull_request:
|
10 |
+
# branches:
|
11 |
+
# - master
|
12 |
+
# branches-ignore:
|
13 |
+
# - development
|
14 |
+
|
15 |
+
jobs:
|
16 |
+
lint:
|
17 |
+
runs-on: ubuntu-latest
|
18 |
+
steps:
|
19 |
+
- name: Checkout Code
|
20 |
+
uses: actions/checkout@v3
|
21 |
+
- name: Set up Python 3.10
|
22 |
+
uses: actions/setup-python@v3
|
23 |
+
with:
|
24 |
+
python-version: 3.10.6
|
25 |
+
- uses: actions/cache@v2
|
26 |
+
with:
|
27 |
+
path: ~/.cache/pip
|
28 |
+
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
29 |
+
restore-keys: |
|
30 |
+
${{ runner.os }}-pip-
|
31 |
+
- name: Install PyLint
|
32 |
+
run: |
|
33 |
+
python -m pip install --upgrade pip
|
34 |
+
pip install pylint
|
35 |
+
# This lets PyLint check to see if it can resolve imports
|
36 |
+
- name: Install dependencies
|
37 |
+
run : |
|
38 |
+
export COMMANDLINE_ARGS="--skip-torch-cuda-test --exit"
|
39 |
+
python launch.py
|
40 |
+
- name: Analysing the code with pylint
|
41 |
+
run: |
|
42 |
+
pylint $(git ls-files '*.py')
|
stable-diffusion-webui-master/.github/workflows/run_tests.yaml
ADDED
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: Run basic features tests on CPU with empty SD model
|
2 |
+
|
3 |
+
on:
|
4 |
+
- push
|
5 |
+
- pull_request
|
6 |
+
|
7 |
+
jobs:
|
8 |
+
test:
|
9 |
+
runs-on: ubuntu-latest
|
10 |
+
steps:
|
11 |
+
- name: Checkout Code
|
12 |
+
uses: actions/checkout@v3
|
13 |
+
- name: Set up Python 3.10
|
14 |
+
uses: actions/setup-python@v4
|
15 |
+
with:
|
16 |
+
python-version: 3.10.6
|
17 |
+
- uses: actions/cache@v3
|
18 |
+
with:
|
19 |
+
path: ~/.cache/pip
|
20 |
+
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
21 |
+
restore-keys: ${{ runner.os }}-pip-
|
22 |
+
- name: Run tests
|
23 |
+
run: python launch.py --tests basic_features --no-half --disable-opt-split-attention --use-cpu all --skip-torch-cuda-test
|
24 |
+
- name: Upload main app stdout-stderr
|
25 |
+
uses: actions/upload-artifact@v3
|
26 |
+
if: always()
|
27 |
+
with:
|
28 |
+
name: stdout-stderr
|
29 |
+
path: |
|
30 |
+
test/stdout.txt
|
31 |
+
test/stderr.txt
|
stable-diffusion-webui-master/.gitignore
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
__pycache__
|
2 |
+
*.ckpt
|
3 |
+
*.safetensors
|
4 |
+
*.pth
|
5 |
+
/ESRGAN/*
|
6 |
+
/SwinIR/*
|
7 |
+
/repositories
|
8 |
+
/venv
|
9 |
+
/tmp
|
10 |
+
/model.ckpt
|
11 |
+
/models/**/*
|
12 |
+
/GFPGANv1.3.pth
|
13 |
+
/gfpgan/weights/*.pth
|
14 |
+
/ui-config.json
|
15 |
+
/outputs
|
16 |
+
/config.json
|
17 |
+
/log
|
18 |
+
/webui.settings.bat
|
19 |
+
/embeddings
|
20 |
+
/styles.csv
|
21 |
+
/params.txt
|
22 |
+
/styles.csv.bak
|
23 |
+
/webui-user.bat
|
24 |
+
/webui-user.sh
|
25 |
+
/interrogate
|
26 |
+
/user.css
|
27 |
+
/.idea
|
28 |
+
notification.mp3
|
29 |
+
/SwinIR
|
30 |
+
/textual_inversion
|
31 |
+
.vscode
|
32 |
+
/extensions
|
33 |
+
/test/stdout.txt
|
34 |
+
/test/stderr.txt
|
stable-diffusion-webui-master/.pylintrc
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
# See https://pylint.pycqa.org/en/latest/user_guide/messages/message_control.html
|
2 |
+
[MESSAGES CONTROL]
|
3 |
+
disable=C,R,W,E,I
|
stable-diffusion-webui-master/CODEOWNERS
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
* @AUTOMATIC1111
|
2 |
+
|
3 |
+
# if you were managing a localization and were removed from this file, this is because
|
4 |
+
# the intended way to do localizations now is via extensions. See:
|
5 |
+
# https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Developing-extensions
|
6 |
+
# Make a repo with your localization and since you are still listed as a collaborator
|
7 |
+
# you can add it to the wiki page yourself. This change is because some people complained
|
8 |
+
# the git commit log is cluttered with things unrelated to almost everyone and
|
9 |
+
# because I believe this is the best overall for the project to handle localizations almost
|
10 |
+
# entirely without my oversight.
|
11 |
+
|
12 |
+
|
stable-diffusion-webui-master/README.md
ADDED
@@ -0,0 +1,150 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Stable Diffusion web UI
|
2 |
+
A browser interface based on Gradio library for Stable Diffusion.
|
3 |
+
|
4 |
+

|
5 |
+
|
6 |
+
Check the [custom scripts](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Custom-Scripts) wiki page for extra scripts developed by users.
|
7 |
+
|
8 |
+
## Features
|
9 |
+
[Detailed feature showcase with images](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Features):
|
10 |
+
- Original txt2img and img2img modes
|
11 |
+
- One click install and run script (but you still must install python and git)
|
12 |
+
- Outpainting
|
13 |
+
- Inpainting
|
14 |
+
- Color Sketch
|
15 |
+
- Prompt Matrix
|
16 |
+
- Stable Diffusion Upscale
|
17 |
+
- Attention, specify parts of text that the model should pay more attention to
|
18 |
+
- a man in a ((tuxedo)) - will pay more attention to tuxedo
|
19 |
+
- a man in a (tuxedo:1.21) - alternative syntax
|
20 |
+
- select text and press ctrl+up or ctrl+down to automatically adjust attention to selected text (code contributed by anonymous user)
|
21 |
+
- Loopback, run img2img processing multiple times
|
22 |
+
- X/Y plot, a way to draw a 2 dimensional plot of images with different parameters
|
23 |
+
- Textual Inversion
|
24 |
+
- have as many embeddings as you want and use any names you like for them
|
25 |
+
- use multiple embeddings with different numbers of vectors per token
|
26 |
+
- works with half precision floating point numbers
|
27 |
+
- train embeddings on 8GB (also reports of 6GB working)
|
28 |
+
- Extras tab with:
|
29 |
+
- GFPGAN, neural network that fixes faces
|
30 |
+
- CodeFormer, face restoration tool as an alternative to GFPGAN
|
31 |
+
- RealESRGAN, neural network upscaler
|
32 |
+
- ESRGAN, neural network upscaler with a lot of third party models
|
33 |
+
- SwinIR and Swin2SR([see here](https://github.com/AUTOMATIC1111/stable-diffusion-webui/pull/2092)), neural network upscalers
|
34 |
+
- LDSR, Latent diffusion super resolution upscaling
|
35 |
+
- Resizing aspect ratio options
|
36 |
+
- Sampling method selection
|
37 |
+
- Adjust sampler eta values (noise multiplier)
|
38 |
+
- More advanced noise setting options
|
39 |
+
- Interrupt processing at any time
|
40 |
+
- 4GB video card support (also reports of 2GB working)
|
41 |
+
- Correct seeds for batches
|
42 |
+
- Live prompt token length validation
|
43 |
+
- Generation parameters
|
44 |
+
- parameters you used to generate images are saved with that image
|
45 |
+
- in PNG chunks for PNG, in EXIF for JPEG
|
46 |
+
- can drag the image to PNG info tab to restore generation parameters and automatically copy them into UI
|
47 |
+
- can be disabled in settings
|
48 |
+
- drag and drop an image/text-parameters to promptbox
|
49 |
+
- Read Generation Parameters Button, loads parameters in promptbox to UI
|
50 |
+
- Settings page
|
51 |
+
- Running arbitrary python code from UI (must run with --allow-code to enable)
|
52 |
+
- Mouseover hints for most UI elements
|
53 |
+
- Possible to change defaults/mix/max/step values for UI elements via text config
|
54 |
+
- Random artist button
|
55 |
+
- Tiling support, a checkbox to create images that can be tiled like textures
|
56 |
+
- Progress bar and live image generation preview
|
57 |
+
- Negative prompt, an extra text field that allows you to list what you don't want to see in generated image
|
58 |
+
- Styles, a way to save part of prompt and easily apply them via dropdown later
|
59 |
+
- Variations, a way to generate same image but with tiny differences
|
60 |
+
- Seed resizing, a way to generate same image but at slightly different resolution
|
61 |
+
- CLIP interrogator, a button that tries to guess prompt from an image
|
62 |
+
- Prompt Editing, a way to change prompt mid-generation, say to start making a watermelon and switch to anime girl midway
|
63 |
+
- Batch Processing, process a group of files using img2img
|
64 |
+
- Img2img Alternative, reverse Euler method of cross attention control
|
65 |
+
- Highres Fix, a convenience option to produce high resolution pictures in one click without usual distortions
|
66 |
+
- Reloading checkpoints on the fly
|
67 |
+
- Checkpoint Merger, a tab that allows you to merge up to 3 checkpoints into one
|
68 |
+
- [Custom scripts](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Custom-Scripts) with many extensions from community
|
69 |
+
- [Composable-Diffusion](https://energy-based-model.github.io/Compositional-Visual-Generation-with-Composable-Diffusion-Models/), a way to use multiple prompts at once
|
70 |
+
- separate prompts using uppercase `AND`
|
71 |
+
- also supports weights for prompts: `a cat :1.2 AND a dog AND a penguin :2.2`
|
72 |
+
- No token limit for prompts (original stable diffusion lets you use up to 75 tokens)
|
73 |
+
- DeepDanbooru integration, creates danbooru style tags for anime prompts
|
74 |
+
- [xformers](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Xformers), major speed increase for select cards: (add --xformers to commandline args)
|
75 |
+
- via extension: [History tab](https://github.com/yfszzx/stable-diffusion-webui-images-browser): view, direct and delete images conveniently within the UI
|
76 |
+
- Generate forever option
|
77 |
+
- Training tab
|
78 |
+
- hypernetworks and embeddings options
|
79 |
+
- Preprocessing images: cropping, mirroring, autotagging using BLIP or deepdanbooru (for anime)
|
80 |
+
- Clip skip
|
81 |
+
- Use Hypernetworks
|
82 |
+
- Use VAEs
|
83 |
+
- Estimated completion time in progress bar
|
84 |
+
- API
|
85 |
+
- Support for dedicated [inpainting model](https://github.com/runwayml/stable-diffusion#inpainting-with-stable-diffusion) by RunwayML.
|
86 |
+
- via extension: [Aesthetic Gradients](https://github.com/AUTOMATIC1111/stable-diffusion-webui-aesthetic-gradients), a way to generate images with a specific aesthetic by using clip images embds (implementation of [https://github.com/vicgalle/stable-diffusion-aesthetic-gradients](https://github.com/vicgalle/stable-diffusion-aesthetic-gradients))
|
87 |
+
- [Stable Diffusion 2.0](https://github.com/Stability-AI/stablediffusion) support - see [wiki](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Features#stable-diffusion-20) for instructions
|
88 |
+
|
89 |
+
## Installation and Running
|
90 |
+
Make sure the required [dependencies](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Dependencies) are met and follow the instructions available for both [NVidia](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Install-and-Run-on-NVidia-GPUs) (recommended) and [AMD](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Install-and-Run-on-AMD-GPUs) GPUs.
|
91 |
+
|
92 |
+
Alternatively, use online services (like Google Colab):
|
93 |
+
|
94 |
+
- [List of Online Services](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Online-Services)
|
95 |
+
|
96 |
+
### Automatic Installation on Windows
|
97 |
+
1. Install [Python 3.10.6](https://www.python.org/downloads/windows/), checking "Add Python to PATH"
|
98 |
+
2. Install [git](https://git-scm.com/download/win).
|
99 |
+
3. Download the stable-diffusion-webui repository, for example by running `git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui.git`.
|
100 |
+
4. Place `model.ckpt` in the `models` directory (see [dependencies](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Dependencies) for where to get it).
|
101 |
+
5. _*(Optional)*_ Place `GFPGANv1.4.pth` in the base directory, alongside `webui.py` (see [dependencies](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Dependencies) for where to get it).
|
102 |
+
6. Run `webui-user.bat` from Windows Explorer as normal, non-administrator, user.
|
103 |
+
|
104 |
+
### Automatic Installation on Linux
|
105 |
+
1. Install the dependencies:
|
106 |
+
```bash
|
107 |
+
# Debian-based:
|
108 |
+
sudo apt install wget git python3 python3-venv
|
109 |
+
# Red Hat-based:
|
110 |
+
sudo dnf install wget git python3
|
111 |
+
# Arch-based:
|
112 |
+
sudo pacman -S wget git python3
|
113 |
+
```
|
114 |
+
2. To install in `/home/$(whoami)/stable-diffusion-webui/`, run:
|
115 |
+
```bash
|
116 |
+
bash <(wget -qO- https://raw.githubusercontent.com/AUTOMATIC1111/stable-diffusion-webui/master/webui.sh)
|
117 |
+
```
|
118 |
+
|
119 |
+
### Installation on Apple Silicon
|
120 |
+
|
121 |
+
Find the instructions [here](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Installation-on-Apple-Silicon).
|
122 |
+
|
123 |
+
## Contributing
|
124 |
+
Here's how to add code to this repo: [Contributing](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Contributing)
|
125 |
+
|
126 |
+
## Documentation
|
127 |
+
The documentation was moved from this README over to the project's [wiki](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki).
|
128 |
+
|
129 |
+
## Credits
|
130 |
+
- Stable Diffusion - https://github.com/CompVis/stable-diffusion, https://github.com/CompVis/taming-transformers
|
131 |
+
- k-diffusion - https://github.com/crowsonkb/k-diffusion.git
|
132 |
+
- GFPGAN - https://github.com/TencentARC/GFPGAN.git
|
133 |
+
- CodeFormer - https://github.com/sczhou/CodeFormer
|
134 |
+
- ESRGAN - https://github.com/xinntao/ESRGAN
|
135 |
+
- SwinIR - https://github.com/JingyunLiang/SwinIR
|
136 |
+
- Swin2SR - https://github.com/mv-lab/swin2sr
|
137 |
+
- LDSR - https://github.com/Hafiidz/latent-diffusion
|
138 |
+
- Ideas for optimizations - https://github.com/basujindal/stable-diffusion
|
139 |
+
- Cross Attention layer optimization - Doggettx - https://github.com/Doggettx/stable-diffusion, original idea for prompt editing.
|
140 |
+
- Cross Attention layer optimization - InvokeAI, lstein - https://github.com/invoke-ai/InvokeAI (originally http://github.com/lstein/stable-diffusion)
|
141 |
+
- Textual Inversion - Rinon Gal - https://github.com/rinongal/textual_inversion (we're not using his code, but we are using his ideas).
|
142 |
+
- Idea for SD upscale - https://github.com/jquesnelle/txt2imghd
|
143 |
+
- Noise generation for outpainting mk2 - https://github.com/parlance-zz/g-diffuser-bot
|
144 |
+
- CLIP interrogator idea and borrowing some code - https://github.com/pharmapsychotic/clip-interrogator
|
145 |
+
- Idea for Composable Diffusion - https://github.com/energy-based-model/Compositional-Visual-Generation-with-Composable-Diffusion-Models-PyTorch
|
146 |
+
- xformers - https://github.com/facebookresearch/xformers
|
147 |
+
- DeepDanbooru - interrogator for anime diffusers https://github.com/KichangKim/DeepDanbooru
|
148 |
+
- Security advice - RyotaK
|
149 |
+
- Initial Gradio script - posted on 4chan by an Anonymous user. Thank you Anonymous user.
|
150 |
+
- (You)
|
stable-diffusion-webui-master/artists.csv
ADDED
The diff for this file is too large to render.
See raw diff
|
|
stable-diffusion-webui-master/embeddings/Place Textual Inversion embeddings here.txt
ADDED
File without changes
|
stable-diffusion-webui-master/environment-wsl2.yaml
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
name: automatic
|
2 |
+
channels:
|
3 |
+
- pytorch
|
4 |
+
- defaults
|
5 |
+
dependencies:
|
6 |
+
- python=3.10
|
7 |
+
- pip=22.2.2
|
8 |
+
- cudatoolkit=11.3
|
9 |
+
- pytorch=1.12.1
|
10 |
+
- torchvision=0.13.1
|
11 |
+
- numpy=1.23.1
|
stable-diffusion-webui-master/extensions/put extensions here.txt
ADDED
File without changes
|
stable-diffusion-webui-master/javascript/aspectRatioOverlay.js
ADDED
@@ -0,0 +1,108 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
let currentWidth = null;
|
3 |
+
let currentHeight = null;
|
4 |
+
let arFrameTimeout = setTimeout(function(){},0);
|
5 |
+
|
6 |
+
function dimensionChange(e, is_width, is_height){
|
7 |
+
|
8 |
+
if(is_width){
|
9 |
+
currentWidth = e.target.value*1.0
|
10 |
+
}
|
11 |
+
if(is_height){
|
12 |
+
currentHeight = e.target.value*1.0
|
13 |
+
}
|
14 |
+
|
15 |
+
var inImg2img = Boolean(gradioApp().querySelector("button.rounded-t-lg.border-gray-200"))
|
16 |
+
|
17 |
+
if(!inImg2img){
|
18 |
+
return;
|
19 |
+
}
|
20 |
+
|
21 |
+
var targetElement = null;
|
22 |
+
|
23 |
+
var tabIndex = get_tab_index('mode_img2img')
|
24 |
+
if(tabIndex == 0){
|
25 |
+
targetElement = gradioApp().querySelector('div[data-testid=image] img');
|
26 |
+
} else if(tabIndex == 1){
|
27 |
+
targetElement = gradioApp().querySelector('#img2maskimg div[data-testid=image] img');
|
28 |
+
}
|
29 |
+
|
30 |
+
if(targetElement){
|
31 |
+
|
32 |
+
var arPreviewRect = gradioApp().querySelector('#imageARPreview');
|
33 |
+
if(!arPreviewRect){
|
34 |
+
arPreviewRect = document.createElement('div')
|
35 |
+
arPreviewRect.id = "imageARPreview";
|
36 |
+
gradioApp().getRootNode().appendChild(arPreviewRect)
|
37 |
+
}
|
38 |
+
|
39 |
+
|
40 |
+
|
41 |
+
var viewportOffset = targetElement.getBoundingClientRect();
|
42 |
+
|
43 |
+
viewportscale = Math.min( targetElement.clientWidth/targetElement.naturalWidth, targetElement.clientHeight/targetElement.naturalHeight )
|
44 |
+
|
45 |
+
scaledx = targetElement.naturalWidth*viewportscale
|
46 |
+
scaledy = targetElement.naturalHeight*viewportscale
|
47 |
+
|
48 |
+
cleintRectTop = (viewportOffset.top+window.scrollY)
|
49 |
+
cleintRectLeft = (viewportOffset.left+window.scrollX)
|
50 |
+
cleintRectCentreY = cleintRectTop + (targetElement.clientHeight/2)
|
51 |
+
cleintRectCentreX = cleintRectLeft + (targetElement.clientWidth/2)
|
52 |
+
|
53 |
+
viewRectTop = cleintRectCentreY-(scaledy/2)
|
54 |
+
viewRectLeft = cleintRectCentreX-(scaledx/2)
|
55 |
+
arRectWidth = scaledx
|
56 |
+
arRectHeight = scaledy
|
57 |
+
|
58 |
+
arscale = Math.min( arRectWidth/currentWidth, arRectHeight/currentHeight )
|
59 |
+
arscaledx = currentWidth*arscale
|
60 |
+
arscaledy = currentHeight*arscale
|
61 |
+
|
62 |
+
arRectTop = cleintRectCentreY-(arscaledy/2)
|
63 |
+
arRectLeft = cleintRectCentreX-(arscaledx/2)
|
64 |
+
arRectWidth = arscaledx
|
65 |
+
arRectHeight = arscaledy
|
66 |
+
|
67 |
+
arPreviewRect.style.top = arRectTop+'px';
|
68 |
+
arPreviewRect.style.left = arRectLeft+'px';
|
69 |
+
arPreviewRect.style.width = arRectWidth+'px';
|
70 |
+
arPreviewRect.style.height = arRectHeight+'px';
|
71 |
+
|
72 |
+
clearTimeout(arFrameTimeout);
|
73 |
+
arFrameTimeout = setTimeout(function(){
|
74 |
+
arPreviewRect.style.display = 'none';
|
75 |
+
},2000);
|
76 |
+
|
77 |
+
arPreviewRect.style.display = 'block';
|
78 |
+
|
79 |
+
}
|
80 |
+
|
81 |
+
}
|
82 |
+
|
83 |
+
|
84 |
+
onUiUpdate(function(){
|
85 |
+
var arPreviewRect = gradioApp().querySelector('#imageARPreview');
|
86 |
+
if(arPreviewRect){
|
87 |
+
arPreviewRect.style.display = 'none';
|
88 |
+
}
|
89 |
+
var inImg2img = Boolean(gradioApp().querySelector("button.rounded-t-lg.border-gray-200"))
|
90 |
+
if(inImg2img){
|
91 |
+
let inputs = gradioApp().querySelectorAll('input');
|
92 |
+
inputs.forEach(function(e){
|
93 |
+
var is_width = e.parentElement.id == "img2img_width"
|
94 |
+
var is_height = e.parentElement.id == "img2img_height"
|
95 |
+
|
96 |
+
if((is_width || is_height) && !e.classList.contains('scrollwatch')){
|
97 |
+
e.addEventListener('input', function(e){dimensionChange(e, is_width, is_height)} )
|
98 |
+
e.classList.add('scrollwatch')
|
99 |
+
}
|
100 |
+
if(is_width){
|
101 |
+
currentWidth = e.value*1.0
|
102 |
+
}
|
103 |
+
if(is_height){
|
104 |
+
currentHeight = e.value*1.0
|
105 |
+
}
|
106 |
+
})
|
107 |
+
}
|
108 |
+
});
|
stable-diffusion-webui-master/javascript/contextMenus.js
ADDED
@@ -0,0 +1,177 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
contextMenuInit = function(){
|
3 |
+
let eventListenerApplied=false;
|
4 |
+
let menuSpecs = new Map();
|
5 |
+
|
6 |
+
const uid = function(){
|
7 |
+
return Date.now().toString(36) + Math.random().toString(36).substr(2);
|
8 |
+
}
|
9 |
+
|
10 |
+
function showContextMenu(event,element,menuEntries){
|
11 |
+
let posx = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
|
12 |
+
let posy = event.clientY + document.body.scrollTop + document.documentElement.scrollTop;
|
13 |
+
|
14 |
+
let oldMenu = gradioApp().querySelector('#context-menu')
|
15 |
+
if(oldMenu){
|
16 |
+
oldMenu.remove()
|
17 |
+
}
|
18 |
+
|
19 |
+
let tabButton = uiCurrentTab
|
20 |
+
let baseStyle = window.getComputedStyle(tabButton)
|
21 |
+
|
22 |
+
const contextMenu = document.createElement('nav')
|
23 |
+
contextMenu.id = "context-menu"
|
24 |
+
contextMenu.style.background = baseStyle.background
|
25 |
+
contextMenu.style.color = baseStyle.color
|
26 |
+
contextMenu.style.fontFamily = baseStyle.fontFamily
|
27 |
+
contextMenu.style.top = posy+'px'
|
28 |
+
contextMenu.style.left = posx+'px'
|
29 |
+
|
30 |
+
|
31 |
+
|
32 |
+
const contextMenuList = document.createElement('ul')
|
33 |
+
contextMenuList.className = 'context-menu-items';
|
34 |
+
contextMenu.append(contextMenuList);
|
35 |
+
|
36 |
+
menuEntries.forEach(function(entry){
|
37 |
+
let contextMenuEntry = document.createElement('a')
|
38 |
+
contextMenuEntry.innerHTML = entry['name']
|
39 |
+
contextMenuEntry.addEventListener("click", function(e) {
|
40 |
+
entry['func']();
|
41 |
+
})
|
42 |
+
contextMenuList.append(contextMenuEntry);
|
43 |
+
|
44 |
+
})
|
45 |
+
|
46 |
+
gradioApp().getRootNode().appendChild(contextMenu)
|
47 |
+
|
48 |
+
let menuWidth = contextMenu.offsetWidth + 4;
|
49 |
+
let menuHeight = contextMenu.offsetHeight + 4;
|
50 |
+
|
51 |
+
let windowWidth = window.innerWidth;
|
52 |
+
let windowHeight = window.innerHeight;
|
53 |
+
|
54 |
+
if ( (windowWidth - posx) < menuWidth ) {
|
55 |
+
contextMenu.style.left = windowWidth - menuWidth + "px";
|
56 |
+
}
|
57 |
+
|
58 |
+
if ( (windowHeight - posy) < menuHeight ) {
|
59 |
+
contextMenu.style.top = windowHeight - menuHeight + "px";
|
60 |
+
}
|
61 |
+
|
62 |
+
}
|
63 |
+
|
64 |
+
function appendContextMenuOption(targetEmementSelector,entryName,entryFunction){
|
65 |
+
|
66 |
+
currentItems = menuSpecs.get(targetEmementSelector)
|
67 |
+
|
68 |
+
if(!currentItems){
|
69 |
+
currentItems = []
|
70 |
+
menuSpecs.set(targetEmementSelector,currentItems);
|
71 |
+
}
|
72 |
+
let newItem = {'id':targetEmementSelector+'_'+uid(),
|
73 |
+
'name':entryName,
|
74 |
+
'func':entryFunction,
|
75 |
+
'isNew':true}
|
76 |
+
|
77 |
+
currentItems.push(newItem)
|
78 |
+
return newItem['id']
|
79 |
+
}
|
80 |
+
|
81 |
+
function removeContextMenuOption(uid){
|
82 |
+
menuSpecs.forEach(function(v,k) {
|
83 |
+
let index = -1
|
84 |
+
v.forEach(function(e,ei){if(e['id']==uid){index=ei}})
|
85 |
+
if(index>=0){
|
86 |
+
v.splice(index, 1);
|
87 |
+
}
|
88 |
+
})
|
89 |
+
}
|
90 |
+
|
91 |
+
function addContextMenuEventListener(){
|
92 |
+
if(eventListenerApplied){
|
93 |
+
return;
|
94 |
+
}
|
95 |
+
gradioApp().addEventListener("click", function(e) {
|
96 |
+
let source = e.composedPath()[0]
|
97 |
+
if(source.id && source.id.indexOf('check_progress')>-1){
|
98 |
+
return
|
99 |
+
}
|
100 |
+
|
101 |
+
let oldMenu = gradioApp().querySelector('#context-menu')
|
102 |
+
if(oldMenu){
|
103 |
+
oldMenu.remove()
|
104 |
+
}
|
105 |
+
});
|
106 |
+
gradioApp().addEventListener("contextmenu", function(e) {
|
107 |
+
let oldMenu = gradioApp().querySelector('#context-menu')
|
108 |
+
if(oldMenu){
|
109 |
+
oldMenu.remove()
|
110 |
+
}
|
111 |
+
menuSpecs.forEach(function(v,k) {
|
112 |
+
if(e.composedPath()[0].matches(k)){
|
113 |
+
showContextMenu(e,e.composedPath()[0],v)
|
114 |
+
e.preventDefault()
|
115 |
+
return
|
116 |
+
}
|
117 |
+
})
|
118 |
+
});
|
119 |
+
eventListenerApplied=true
|
120 |
+
|
121 |
+
}
|
122 |
+
|
123 |
+
return [appendContextMenuOption, removeContextMenuOption, addContextMenuEventListener]
|
124 |
+
}
|
125 |
+
|
126 |
+
initResponse = contextMenuInit();
|
127 |
+
appendContextMenuOption = initResponse[0];
|
128 |
+
removeContextMenuOption = initResponse[1];
|
129 |
+
addContextMenuEventListener = initResponse[2];
|
130 |
+
|
131 |
+
(function(){
|
132 |
+
//Start example Context Menu Items
|
133 |
+
let generateOnRepeat = function(genbuttonid,interruptbuttonid){
|
134 |
+
let genbutton = gradioApp().querySelector(genbuttonid);
|
135 |
+
let interruptbutton = gradioApp().querySelector(interruptbuttonid);
|
136 |
+
if(!interruptbutton.offsetParent){
|
137 |
+
genbutton.click();
|
138 |
+
}
|
139 |
+
clearInterval(window.generateOnRepeatInterval)
|
140 |
+
window.generateOnRepeatInterval = setInterval(function(){
|
141 |
+
if(!interruptbutton.offsetParent){
|
142 |
+
genbutton.click();
|
143 |
+
}
|
144 |
+
},
|
145 |
+
500)
|
146 |
+
}
|
147 |
+
|
148 |
+
appendContextMenuOption('#txt2img_generate','Generate forever',function(){
|
149 |
+
generateOnRepeat('#txt2img_generate','#txt2img_interrupt');
|
150 |
+
})
|
151 |
+
appendContextMenuOption('#img2img_generate','Generate forever',function(){
|
152 |
+
generateOnRepeat('#img2img_generate','#img2img_interrupt');
|
153 |
+
})
|
154 |
+
|
155 |
+
let cancelGenerateForever = function(){
|
156 |
+
clearInterval(window.generateOnRepeatInterval)
|
157 |
+
}
|
158 |
+
|
159 |
+
appendContextMenuOption('#txt2img_interrupt','Cancel generate forever',cancelGenerateForever)
|
160 |
+
appendContextMenuOption('#txt2img_generate', 'Cancel generate forever',cancelGenerateForever)
|
161 |
+
appendContextMenuOption('#img2img_interrupt','Cancel generate forever',cancelGenerateForever)
|
162 |
+
appendContextMenuOption('#img2img_generate', 'Cancel generate forever',cancelGenerateForever)
|
163 |
+
|
164 |
+
appendContextMenuOption('#roll','Roll three',
|
165 |
+
function(){
|
166 |
+
let rollbutton = get_uiCurrentTabContent().querySelector('#roll');
|
167 |
+
setTimeout(function(){rollbutton.click()},100)
|
168 |
+
setTimeout(function(){rollbutton.click()},200)
|
169 |
+
setTimeout(function(){rollbutton.click()},300)
|
170 |
+
}
|
171 |
+
)
|
172 |
+
})();
|
173 |
+
//End example Context Menu Items
|
174 |
+
|
175 |
+
onUiUpdate(function(){
|
176 |
+
addContextMenuEventListener()
|
177 |
+
});
|
stable-diffusion-webui-master/javascript/dragdrop.js
ADDED
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
// allows drag-dropping files into gradio image elements, and also pasting images from clipboard
|
2 |
+
|
3 |
+
function isValidImageList( files ) {
|
4 |
+
return files && files?.length === 1 && ['image/png', 'image/gif', 'image/jpeg'].includes(files[0].type);
|
5 |
+
}
|
6 |
+
|
7 |
+
function dropReplaceImage( imgWrap, files ) {
|
8 |
+
if ( ! isValidImageList( files ) ) {
|
9 |
+
return;
|
10 |
+
}
|
11 |
+
|
12 |
+
imgWrap.querySelector('.modify-upload button + button, .touch-none + div button + button')?.click();
|
13 |
+
const callback = () => {
|
14 |
+
const fileInput = imgWrap.querySelector('input[type="file"]');
|
15 |
+
if ( fileInput ) {
|
16 |
+
fileInput.files = files;
|
17 |
+
fileInput.dispatchEvent(new Event('change'));
|
18 |
+
}
|
19 |
+
};
|
20 |
+
|
21 |
+
if ( imgWrap.closest('#pnginfo_image') ) {
|
22 |
+
// special treatment for PNG Info tab, wait for fetch request to finish
|
23 |
+
const oldFetch = window.fetch;
|
24 |
+
window.fetch = async (input, options) => {
|
25 |
+
const response = await oldFetch(input, options);
|
26 |
+
if ( 'api/predict/' === input ) {
|
27 |
+
const content = await response.text();
|
28 |
+
window.fetch = oldFetch;
|
29 |
+
window.requestAnimationFrame( () => callback() );
|
30 |
+
return new Response(content, {
|
31 |
+
status: response.status,
|
32 |
+
statusText: response.statusText,
|
33 |
+
headers: response.headers
|
34 |
+
})
|
35 |
+
}
|
36 |
+
return response;
|
37 |
+
};
|
38 |
+
} else {
|
39 |
+
window.requestAnimationFrame( () => callback() );
|
40 |
+
}
|
41 |
+
}
|
42 |
+
|
43 |
+
window.document.addEventListener('dragover', e => {
|
44 |
+
const target = e.composedPath()[0];
|
45 |
+
const imgWrap = target.closest('[data-testid="image"]');
|
46 |
+
if ( !imgWrap && target.placeholder && target.placeholder.indexOf("Prompt") == -1) {
|
47 |
+
return;
|
48 |
+
}
|
49 |
+
e.stopPropagation();
|
50 |
+
e.preventDefault();
|
51 |
+
e.dataTransfer.dropEffect = 'copy';
|
52 |
+
});
|
53 |
+
|
54 |
+
window.document.addEventListener('drop', e => {
|
55 |
+
const target = e.composedPath()[0];
|
56 |
+
if (target.placeholder.indexOf("Prompt") == -1) {
|
57 |
+
return;
|
58 |
+
}
|
59 |
+
const imgWrap = target.closest('[data-testid="image"]');
|
60 |
+
if ( !imgWrap ) {
|
61 |
+
return;
|
62 |
+
}
|
63 |
+
e.stopPropagation();
|
64 |
+
e.preventDefault();
|
65 |
+
const files = e.dataTransfer.files;
|
66 |
+
dropReplaceImage( imgWrap, files );
|
67 |
+
});
|
68 |
+
|
69 |
+
window.addEventListener('paste', e => {
|
70 |
+
const files = e.clipboardData.files;
|
71 |
+
if ( ! isValidImageList( files ) ) {
|
72 |
+
return;
|
73 |
+
}
|
74 |
+
|
75 |
+
const visibleImageFields = [...gradioApp().querySelectorAll('[data-testid="image"]')]
|
76 |
+
.filter(el => uiElementIsVisible(el));
|
77 |
+
if ( ! visibleImageFields.length ) {
|
78 |
+
return;
|
79 |
+
}
|
80 |
+
|
81 |
+
const firstFreeImageField = visibleImageFields
|
82 |
+
.filter(el => el.querySelector('input[type=file]'))?.[0];
|
83 |
+
|
84 |
+
dropReplaceImage(
|
85 |
+
firstFreeImageField ?
|
86 |
+
firstFreeImageField :
|
87 |
+
visibleImageFields[visibleImageFields.length - 1]
|
88 |
+
, files );
|
89 |
+
});
|
stable-diffusion-webui-master/javascript/edit-attention.js
ADDED
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
addEventListener('keydown', (event) => {
|
2 |
+
let target = event.originalTarget || event.composedPath()[0];
|
3 |
+
if (!target.matches("#toprow textarea.gr-text-input[placeholder]")) return;
|
4 |
+
if (! (event.metaKey || event.ctrlKey)) return;
|
5 |
+
|
6 |
+
|
7 |
+
let plus = "ArrowUp"
|
8 |
+
let minus = "ArrowDown"
|
9 |
+
if (event.key != plus && event.key != minus) return;
|
10 |
+
|
11 |
+
let selectionStart = target.selectionStart;
|
12 |
+
let selectionEnd = target.selectionEnd;
|
13 |
+
// If the user hasn't selected anything, let's select their current parenthesis block
|
14 |
+
if (selectionStart === selectionEnd) {
|
15 |
+
// Find opening parenthesis around current cursor
|
16 |
+
const before = target.value.substring(0, selectionStart);
|
17 |
+
let beforeParen = before.lastIndexOf("(");
|
18 |
+
if (beforeParen == -1) return;
|
19 |
+
let beforeParenClose = before.lastIndexOf(")");
|
20 |
+
while (beforeParenClose !== -1 && beforeParenClose > beforeParen) {
|
21 |
+
beforeParen = before.lastIndexOf("(", beforeParen - 1);
|
22 |
+
beforeParenClose = before.lastIndexOf(")", beforeParenClose - 1);
|
23 |
+
}
|
24 |
+
|
25 |
+
// Find closing parenthesis around current cursor
|
26 |
+
const after = target.value.substring(selectionStart);
|
27 |
+
let afterParen = after.indexOf(")");
|
28 |
+
if (afterParen == -1) return;
|
29 |
+
let afterParenOpen = after.indexOf("(");
|
30 |
+
while (afterParenOpen !== -1 && afterParen > afterParenOpen) {
|
31 |
+
afterParen = after.indexOf(")", afterParen + 1);
|
32 |
+
afterParenOpen = after.indexOf("(", afterParenOpen + 1);
|
33 |
+
}
|
34 |
+
if (beforeParen === -1 || afterParen === -1) return;
|
35 |
+
|
36 |
+
// Set the selection to the text between the parenthesis
|
37 |
+
const parenContent = target.value.substring(beforeParen + 1, selectionStart + afterParen);
|
38 |
+
const lastColon = parenContent.lastIndexOf(":");
|
39 |
+
selectionStart = beforeParen + 1;
|
40 |
+
selectionEnd = selectionStart + lastColon;
|
41 |
+
target.setSelectionRange(selectionStart, selectionEnd);
|
42 |
+
}
|
43 |
+
|
44 |
+
event.preventDefault();
|
45 |
+
|
46 |
+
if (selectionStart == 0 || target.value[selectionStart - 1] != "(") {
|
47 |
+
target.value = target.value.slice(0, selectionStart) +
|
48 |
+
"(" + target.value.slice(selectionStart, selectionEnd) + ":1.0)" +
|
49 |
+
target.value.slice(selectionEnd);
|
50 |
+
|
51 |
+
target.focus();
|
52 |
+
target.selectionStart = selectionStart + 1;
|
53 |
+
target.selectionEnd = selectionEnd + 1;
|
54 |
+
|
55 |
+
} else {
|
56 |
+
end = target.value.slice(selectionEnd + 1).indexOf(")") + 1;
|
57 |
+
weight = parseFloat(target.value.slice(selectionEnd + 1, selectionEnd + 1 + end));
|
58 |
+
if (isNaN(weight)) return;
|
59 |
+
if (event.key == minus) weight -= 0.1;
|
60 |
+
if (event.key == plus) weight += 0.1;
|
61 |
+
|
62 |
+
weight = parseFloat(weight.toPrecision(12));
|
63 |
+
|
64 |
+
target.value = target.value.slice(0, selectionEnd + 1) +
|
65 |
+
weight +
|
66 |
+
target.value.slice(selectionEnd + 1 + end - 1);
|
67 |
+
|
68 |
+
target.focus();
|
69 |
+
target.selectionStart = selectionStart;
|
70 |
+
target.selectionEnd = selectionEnd;
|
71 |
+
}
|
72 |
+
// Since we've modified a Gradio Textbox component manually, we need to simulate an `input` DOM event to ensure its
|
73 |
+
// internal Svelte data binding remains in sync.
|
74 |
+
target.dispatchEvent(new Event("input", { bubbles: true }));
|
75 |
+
});
|
stable-diffusion-webui-master/javascript/extensions.js
ADDED
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
function extensions_apply(_, _){
|
3 |
+
disable = []
|
4 |
+
update = []
|
5 |
+
gradioApp().querySelectorAll('#extensions input[type="checkbox"]').forEach(function(x){
|
6 |
+
if(x.name.startsWith("enable_") && ! x.checked)
|
7 |
+
disable.push(x.name.substr(7))
|
8 |
+
|
9 |
+
if(x.name.startsWith("update_") && x.checked)
|
10 |
+
update.push(x.name.substr(7))
|
11 |
+
})
|
12 |
+
|
13 |
+
restart_reload()
|
14 |
+
|
15 |
+
return [JSON.stringify(disable), JSON.stringify(update)]
|
16 |
+
}
|
17 |
+
|
18 |
+
function extensions_check(){
|
19 |
+
gradioApp().querySelectorAll('#extensions .extension_status').forEach(function(x){
|
20 |
+
x.innerHTML = "Loading..."
|
21 |
+
})
|
22 |
+
|
23 |
+
return []
|
24 |
+
}
|
25 |
+
|
26 |
+
function install_extension_from_index(button, url){
|
27 |
+
button.disabled = "disabled"
|
28 |
+
button.value = "Installing..."
|
29 |
+
|
30 |
+
textarea = gradioApp().querySelector('#extension_to_install textarea')
|
31 |
+
textarea.value = url
|
32 |
+
textarea.dispatchEvent(new Event("input", { bubbles: true }))
|
33 |
+
|
34 |
+
gradioApp().querySelector('#install_extension_button').click()
|
35 |
+
}
|
stable-diffusion-webui-master/javascript/generationParams.js
ADDED
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
// attaches listeners to the txt2img and img2img galleries to update displayed generation param text when the image changes
|
2 |
+
|
3 |
+
let txt2img_gallery, img2img_gallery, modal = undefined;
|
4 |
+
onUiUpdate(function(){
|
5 |
+
if (!txt2img_gallery) {
|
6 |
+
txt2img_gallery = attachGalleryListeners("txt2img")
|
7 |
+
}
|
8 |
+
if (!img2img_gallery) {
|
9 |
+
img2img_gallery = attachGalleryListeners("img2img")
|
10 |
+
}
|
11 |
+
if (!modal) {
|
12 |
+
modal = gradioApp().getElementById('lightboxModal')
|
13 |
+
modalObserver.observe(modal, { attributes : true, attributeFilter : ['style'] });
|
14 |
+
}
|
15 |
+
});
|
16 |
+
|
17 |
+
let modalObserver = new MutationObserver(function(mutations) {
|
18 |
+
mutations.forEach(function(mutationRecord) {
|
19 |
+
let selectedTab = gradioApp().querySelector('#tabs div button.bg-white')?.innerText
|
20 |
+
if (mutationRecord.target.style.display === 'none' && selectedTab === 'txt2img' || selectedTab === 'img2img')
|
21 |
+
gradioApp().getElementById(selectedTab+"_generation_info_button").click()
|
22 |
+
});
|
23 |
+
});
|
24 |
+
|
25 |
+
function attachGalleryListeners(tab_name) {
|
26 |
+
gallery = gradioApp().querySelector('#'+tab_name+'_gallery')
|
27 |
+
gallery?.addEventListener('click', () => gradioApp().getElementById(tab_name+"_generation_info_button").click());
|
28 |
+
gallery?.addEventListener('keydown', (e) => {
|
29 |
+
if (e.keyCode == 37 || e.keyCode == 39) // left or right arrow
|
30 |
+
gradioApp().getElementById(tab_name+"_generation_info_button").click()
|
31 |
+
});
|
32 |
+
return gallery;
|
33 |
+
}
|
stable-diffusion-webui-master/javascript/hints.js
ADDED
@@ -0,0 +1,129 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
// mouseover tooltips for various UI elements
|
2 |
+
|
3 |
+
titles = {
|
4 |
+
"Sampling steps": "How many times to improve the generated image iteratively; higher values take longer; very low values can produce bad results",
|
5 |
+
"Sampling method": "Which algorithm to use to produce the image",
|
6 |
+
"GFPGAN": "Restore low quality faces using GFPGAN neural network",
|
7 |
+
"Euler a": "Euler Ancestral - very creative, each can get a completely different picture depending on step count, setting steps to higher than 30-40 does not help",
|
8 |
+
"DDIM": "Denoising Diffusion Implicit Models - best at inpainting",
|
9 |
+
|
10 |
+
"Batch count": "How many batches of images to create",
|
11 |
+
"Batch size": "How many image to create in a single batch",
|
12 |
+
"CFG Scale": "Classifier Free Guidance Scale - how strongly the image should conform to prompt - lower values produce more creative results",
|
13 |
+
"Seed": "A value that determines the output of random number generator - if you create an image with same parameters and seed as another image, you'll get the same result",
|
14 |
+
"\u{1f3b2}\ufe0f": "Set seed to -1, which will cause a new random number to be used every time",
|
15 |
+
"\u267b\ufe0f": "Reuse seed from last generation, mostly useful if it was randomed",
|
16 |
+
"\u{1f3a8}": "Add a random artist to the prompt.",
|
17 |
+
"\u2199\ufe0f": "Read generation parameters from prompt or last generation if prompt is empty into user interface.",
|
18 |
+
"\u{1f4c2}": "Open images output directory",
|
19 |
+
"\u{1f4be}": "Save style",
|
20 |
+
"\u{1f4cb}": "Apply selected styles to current prompt",
|
21 |
+
|
22 |
+
"Inpaint a part of image": "Draw a mask over an image, and the script will regenerate the masked area with content according to prompt",
|
23 |
+
"SD upscale": "Upscale image normally, split result into tiles, improve each tile using img2img, merge whole image back",
|
24 |
+
|
25 |
+
"Just resize": "Resize image to target resolution. Unless height and width match, you will get incorrect aspect ratio.",
|
26 |
+
"Crop and resize": "Resize the image so that entirety of target resolution is filled with the image. Crop parts that stick out.",
|
27 |
+
"Resize and fill": "Resize the image so that entirety of image is inside target resolution. Fill empty space with image's colors.",
|
28 |
+
|
29 |
+
"Mask blur": "How much to blur the mask before processing, in pixels.",
|
30 |
+
"Masked content": "What to put inside the masked area before processing it with Stable Diffusion.",
|
31 |
+
"fill": "fill it with colors of the image",
|
32 |
+
"original": "keep whatever was there originally",
|
33 |
+
"latent noise": "fill it with latent space noise",
|
34 |
+
"latent nothing": "fill it with latent space zeroes",
|
35 |
+
"Inpaint at full resolution": "Upscale masked region to target resolution, do inpainting, downscale back and paste into original image",
|
36 |
+
|
37 |
+
"Denoising strength": "Determines how little respect the algorithm should have for image's content. At 0, nothing will change, and at 1 you'll get an unrelated image. With values below 1.0, processing will take less steps than the Sampling Steps slider specifies.",
|
38 |
+
"Denoising strength change factor": "In loopback mode, on each loop the denoising strength is multiplied by this value. <1 means decreasing variety so your sequence will converge on a fixed picture. >1 means increasing variety so your sequence will become more and more chaotic.",
|
39 |
+
|
40 |
+
"Skip": "Stop processing current image and continue processing.",
|
41 |
+
"Interrupt": "Stop processing images and return any results accumulated so far.",
|
42 |
+
"Save": "Write image to a directory (default - log/images) and generation parameters into csv file.",
|
43 |
+
|
44 |
+
"X values": "Separate values for X axis using commas.",
|
45 |
+
"Y values": "Separate values for Y axis using commas.",
|
46 |
+
|
47 |
+
"None": "Do not do anything special",
|
48 |
+
"Prompt matrix": "Separate prompts into parts using vertical pipe character (|) and the script will create a picture for every combination of them (except for the first part, which will be present in all combinations)",
|
49 |
+
"X/Y plot": "Create a grid where images will have different parameters. Use inputs below to specify which parameters will be shared by columns and rows",
|
50 |
+
"Custom code": "Run Python code. Advanced user only. Must run program with --allow-code for this to work",
|
51 |
+
|
52 |
+
"Prompt S/R": "Separate a list of words with commas, and the first word will be used as a keyword: script will search for this word in the prompt, and replace it with others",
|
53 |
+
"Prompt order": "Separate a list of words with commas, and the script will make a variation of prompt with those words for their every possible order",
|
54 |
+
|
55 |
+
"Tiling": "Produce an image that can be tiled.",
|
56 |
+
"Tile overlap": "For SD upscale, how much overlap in pixels should there be between tiles. Tiles overlap so that when they are merged back into one picture, there is no clearly visible seam.",
|
57 |
+
|
58 |
+
"Variation seed": "Seed of a different picture to be mixed into the generation.",
|
59 |
+
"Variation strength": "How strong of a variation to produce. At 0, there will be no effect. At 1, you will get the complete picture with variation seed (except for ancestral samplers, where you will just get something).",
|
60 |
+
"Resize seed from height": "Make an attempt to produce a picture similar to what would have been produced with same seed at specified resolution",
|
61 |
+
"Resize seed from width": "Make an attempt to produce a picture similar to what would have been produced with same seed at specified resolution",
|
62 |
+
|
63 |
+
"Interrogate": "Reconstruct prompt from existing image and put it into the prompt field.",
|
64 |
+
|
65 |
+
"Images filename pattern": "Use following tags to define how filenames for images are chosen: [steps], [cfg], [prompt], [prompt_no_styles], [prompt_spaces], [width], [height], [styles], [sampler], [seed], [model_hash], [model_name], [prompt_words], [date], [datetime], [datetime<Format>], [datetime<Format><Time Zone>], [job_timestamp]; leave empty for default.",
|
66 |
+
"Directory name pattern": "Use following tags to define how subdirectories for images and grids are chosen: [steps], [cfg], [prompt], [prompt_no_styles], [prompt_spaces], [width], [height], [styles], [sampler], [seed], [model_hash], [model_name], [prompt_words], [date], [datetime], [datetime<Format>], [datetime<Format><Time Zone>], [job_timestamp]; leave empty for default.",
|
67 |
+
"Max prompt words": "Set the maximum number of words to be used in the [prompt_words] option; ATTENTION: If the words are too long, they may exceed the maximum length of the file path that the system can handle",
|
68 |
+
|
69 |
+
"Loopback": "Process an image, use it as an input, repeat.",
|
70 |
+
"Loops": "How many times to repeat processing an image and using it as input for the next iteration",
|
71 |
+
|
72 |
+
"Style 1": "Style to apply; styles have components for both positive and negative prompts and apply to both",
|
73 |
+
"Style 2": "Style to apply; styles have components for both positive and negative prompts and apply to both",
|
74 |
+
"Apply style": "Insert selected styles into prompt fields",
|
75 |
+
"Create style": "Save current prompts as a style. If you add the token {prompt} to the text, the style use that as placeholder for your prompt when you use the style in the future.",
|
76 |
+
|
77 |
+
"Checkpoint name": "Loads weights from checkpoint before making images. You can either use hash or a part of filename (as seen in settings) for checkpoint name. Recommended to use with Y axis for less switching.",
|
78 |
+
"Inpainting conditioning mask strength": "Only applies to inpainting models. Determines how strongly to mask off the original image for inpainting and img2img. 1.0 means fully masked, which is the default behaviour. 0.0 means a fully unmasked conditioning. Lower values will help preserve the overall composition of the image, but will struggle with large changes.",
|
79 |
+
|
80 |
+
"vram": "Torch active: Peak amount of VRAM used by Torch during generation, excluding cached data.\nTorch reserved: Peak amount of VRAM allocated by Torch, including all active and cached data.\nSys VRAM: Peak amount of VRAM allocation across all applications / total GPU VRAM (peak utilization%).",
|
81 |
+
|
82 |
+
"Highres. fix": "Use a two step process to partially create an image at smaller resolution, upscale, and then improve details in it without changing composition",
|
83 |
+
"Scale latent": "Uscale the image in latent space. Alternative is to produce the full image from latent representation, upscale that, and then move it back to latent space.",
|
84 |
+
|
85 |
+
"Eta noise seed delta": "If this values is non-zero, it will be added to seed and used to initialize RNG for noises when using samplers with Eta. You can use this to produce even more variation of images, or you can use this to match images of other software if you know what you are doing.",
|
86 |
+
"Do not add watermark to images": "If this option is enabled, watermark will not be added to created images. Warning: if you do not add watermark, you may be behaving in an unethical manner.",
|
87 |
+
|
88 |
+
"Filename word regex": "This regular expression will be used extract words from filename, and they will be joined using the option below into label text used for training. Leave empty to keep filename text as it is.",
|
89 |
+
"Filename join string": "This string will be used to join split words into a single line if the option above is enabled.",
|
90 |
+
|
91 |
+
"Quicksettings list": "List of setting names, separated by commas, for settings that should go to the quick access bar at the top, rather than the usual setting tab. See modules/shared.py for setting names. Requires restarting to apply.",
|
92 |
+
|
93 |
+
"Weighted sum": "Result = A * (1 - M) + B * M",
|
94 |
+
"Add difference": "Result = A + (B - C) * M",
|
95 |
+
|
96 |
+
"Learning rate": "how fast should the training go. Low values will take longer to train, high values may fail to converge (not generate accurate results) and/or may break the embedding (This has happened if you see Loss: nan in the training info textbox. If this happens, you need to manually restore your embedding from an older not-broken backup).\n\nYou can set a single numeric value, or multiple learning rates using the syntax:\n\n rate_1:max_steps_1, rate_2:max_steps_2, ...\n\nEG: 0.005:100, 1e-3:1000, 1e-5\n\nWill train with rate of 0.005 for first 100 steps, then 1e-3 until 1000 steps, then 1e-5 for all remaining steps.",
|
97 |
+
}
|
98 |
+
|
99 |
+
|
100 |
+
onUiUpdate(function(){
|
101 |
+
gradioApp().querySelectorAll('span, button, select, p').forEach(function(span){
|
102 |
+
tooltip = titles[span.textContent];
|
103 |
+
|
104 |
+
if(!tooltip){
|
105 |
+
tooltip = titles[span.value];
|
106 |
+
}
|
107 |
+
|
108 |
+
if(!tooltip){
|
109 |
+
for (const c of span.classList) {
|
110 |
+
if (c in titles) {
|
111 |
+
tooltip = titles[c];
|
112 |
+
break;
|
113 |
+
}
|
114 |
+
}
|
115 |
+
}
|
116 |
+
|
117 |
+
if(tooltip){
|
118 |
+
span.title = tooltip;
|
119 |
+
}
|
120 |
+
})
|
121 |
+
|
122 |
+
gradioApp().querySelectorAll('select').forEach(function(select){
|
123 |
+
if (select.onchange != null) return;
|
124 |
+
|
125 |
+
select.onchange = function(){
|
126 |
+
select.title = titles[select.value] || "";
|
127 |
+
}
|
128 |
+
})
|
129 |
+
})
|
stable-diffusion-webui-master/javascript/imageMaskFix.js
ADDED
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* temporary fix for https://github.com/AUTOMATIC1111/stable-diffusion-webui/issues/668
|
3 |
+
* @see https://github.com/gradio-app/gradio/issues/1721
|
4 |
+
*/
|
5 |
+
window.addEventListener( 'resize', () => imageMaskResize());
|
6 |
+
function imageMaskResize() {
|
7 |
+
const canvases = gradioApp().querySelectorAll('#img2maskimg .touch-none canvas');
|
8 |
+
if ( ! canvases.length ) {
|
9 |
+
canvases_fixed = false;
|
10 |
+
window.removeEventListener( 'resize', imageMaskResize );
|
11 |
+
return;
|
12 |
+
}
|
13 |
+
|
14 |
+
const wrapper = canvases[0].closest('.touch-none');
|
15 |
+
const previewImage = wrapper.previousElementSibling;
|
16 |
+
|
17 |
+
if ( ! previewImage.complete ) {
|
18 |
+
previewImage.addEventListener( 'load', () => imageMaskResize());
|
19 |
+
return;
|
20 |
+
}
|
21 |
+
|
22 |
+
const w = previewImage.width;
|
23 |
+
const h = previewImage.height;
|
24 |
+
const nw = previewImage.naturalWidth;
|
25 |
+
const nh = previewImage.naturalHeight;
|
26 |
+
const portrait = nh > nw;
|
27 |
+
const factor = portrait;
|
28 |
+
|
29 |
+
const wW = Math.min(w, portrait ? h/nh*nw : w/nw*nw);
|
30 |
+
const wH = Math.min(h, portrait ? h/nh*nh : w/nw*nh);
|
31 |
+
|
32 |
+
wrapper.style.width = `${wW}px`;
|
33 |
+
wrapper.style.height = `${wH}px`;
|
34 |
+
wrapper.style.left = `0px`;
|
35 |
+
wrapper.style.top = `0px`;
|
36 |
+
|
37 |
+
canvases.forEach( c => {
|
38 |
+
c.style.width = c.style.height = '';
|
39 |
+
c.style.maxWidth = '100%';
|
40 |
+
c.style.maxHeight = '100%';
|
41 |
+
c.style.objectFit = 'contain';
|
42 |
+
});
|
43 |
+
}
|
44 |
+
|
45 |
+
onUiUpdate(() => imageMaskResize());
|
stable-diffusion-webui-master/javascript/imageParams.js
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
window.onload = (function(){
|
2 |
+
window.addEventListener('drop', e => {
|
3 |
+
const target = e.composedPath()[0];
|
4 |
+
const idx = selected_gallery_index();
|
5 |
+
if (target.placeholder.indexOf("Prompt") == -1) return;
|
6 |
+
|
7 |
+
let prompt_target = get_tab_index('tabs') == 1 ? "img2img_prompt_image" : "txt2img_prompt_image";
|
8 |
+
|
9 |
+
e.stopPropagation();
|
10 |
+
e.preventDefault();
|
11 |
+
const imgParent = gradioApp().getElementById(prompt_target);
|
12 |
+
const files = e.dataTransfer.files;
|
13 |
+
const fileInput = imgParent.querySelector('input[type="file"]');
|
14 |
+
if ( fileInput ) {
|
15 |
+
fileInput.files = files;
|
16 |
+
fileInput.dispatchEvent(new Event('change'));
|
17 |
+
}
|
18 |
+
});
|
19 |
+
});
|
stable-diffusion-webui-master/javascript/imageviewer.js
ADDED
@@ -0,0 +1,276 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
// A full size 'lightbox' preview modal shown when left clicking on gallery previews
|
2 |
+
function closeModal() {
|
3 |
+
gradioApp().getElementById("lightboxModal").style.display = "none";
|
4 |
+
}
|
5 |
+
|
6 |
+
function showModal(event) {
|
7 |
+
const source = event.target || event.srcElement;
|
8 |
+
const modalImage = gradioApp().getElementById("modalImage")
|
9 |
+
const lb = gradioApp().getElementById("lightboxModal")
|
10 |
+
modalImage.src = source.src
|
11 |
+
if (modalImage.style.display === 'none') {
|
12 |
+
lb.style.setProperty('background-image', 'url(' + source.src + ')');
|
13 |
+
}
|
14 |
+
lb.style.display = "block";
|
15 |
+
lb.focus()
|
16 |
+
|
17 |
+
const tabTxt2Img = gradioApp().getElementById("tab_txt2img")
|
18 |
+
const tabImg2Img = gradioApp().getElementById("tab_img2img")
|
19 |
+
// show the save button in modal only on txt2img or img2img tabs
|
20 |
+
if (tabTxt2Img.style.display != "none" || tabImg2Img.style.display != "none") {
|
21 |
+
gradioApp().getElementById("modal_save").style.display = "inline"
|
22 |
+
} else {
|
23 |
+
gradioApp().getElementById("modal_save").style.display = "none"
|
24 |
+
}
|
25 |
+
event.stopPropagation()
|
26 |
+
}
|
27 |
+
|
28 |
+
function negmod(n, m) {
|
29 |
+
return ((n % m) + m) % m;
|
30 |
+
}
|
31 |
+
|
32 |
+
function updateOnBackgroundChange() {
|
33 |
+
const modalImage = gradioApp().getElementById("modalImage")
|
34 |
+
if (modalImage && modalImage.offsetParent) {
|
35 |
+
let allcurrentButtons = gradioApp().querySelectorAll(".gallery-item.transition-all.\\!ring-2")
|
36 |
+
let currentButton = null
|
37 |
+
allcurrentButtons.forEach(function(elem) {
|
38 |
+
if (elem.parentElement.offsetParent) {
|
39 |
+
currentButton = elem;
|
40 |
+
}
|
41 |
+
})
|
42 |
+
|
43 |
+
if (currentButton?.children?.length > 0 && modalImage.src != currentButton.children[0].src) {
|
44 |
+
modalImage.src = currentButton.children[0].src;
|
45 |
+
if (modalImage.style.display === 'none') {
|
46 |
+
modal.style.setProperty('background-image', `url(${modalImage.src})`)
|
47 |
+
}
|
48 |
+
}
|
49 |
+
}
|
50 |
+
}
|
51 |
+
|
52 |
+
function modalImageSwitch(offset) {
|
53 |
+
var allgalleryButtons = gradioApp().querySelectorAll(".gallery-item.transition-all")
|
54 |
+
var galleryButtons = []
|
55 |
+
allgalleryButtons.forEach(function(elem) {
|
56 |
+
if (elem.parentElement.offsetParent) {
|
57 |
+
galleryButtons.push(elem);
|
58 |
+
}
|
59 |
+
})
|
60 |
+
|
61 |
+
if (galleryButtons.length > 1) {
|
62 |
+
var allcurrentButtons = gradioApp().querySelectorAll(".gallery-item.transition-all.\\!ring-2")
|
63 |
+
var currentButton = null
|
64 |
+
allcurrentButtons.forEach(function(elem) {
|
65 |
+
if (elem.parentElement.offsetParent) {
|
66 |
+
currentButton = elem;
|
67 |
+
}
|
68 |
+
})
|
69 |
+
|
70 |
+
var result = -1
|
71 |
+
galleryButtons.forEach(function(v, i) {
|
72 |
+
if (v == currentButton) {
|
73 |
+
result = i
|
74 |
+
}
|
75 |
+
})
|
76 |
+
|
77 |
+
if (result != -1) {
|
78 |
+
nextButton = galleryButtons[negmod((result + offset), galleryButtons.length)]
|
79 |
+
nextButton.click()
|
80 |
+
const modalImage = gradioApp().getElementById("modalImage");
|
81 |
+
const modal = gradioApp().getElementById("lightboxModal");
|
82 |
+
modalImage.src = nextButton.children[0].src;
|
83 |
+
if (modalImage.style.display === 'none') {
|
84 |
+
modal.style.setProperty('background-image', `url(${modalImage.src})`)
|
85 |
+
}
|
86 |
+
setTimeout(function() {
|
87 |
+
modal.focus()
|
88 |
+
}, 10)
|
89 |
+
}
|
90 |
+
}
|
91 |
+
}
|
92 |
+
|
93 |
+
function saveImage(){
|
94 |
+
const tabTxt2Img = gradioApp().getElementById("tab_txt2img")
|
95 |
+
const tabImg2Img = gradioApp().getElementById("tab_img2img")
|
96 |
+
const saveTxt2Img = "save_txt2img"
|
97 |
+
const saveImg2Img = "save_img2img"
|
98 |
+
if (tabTxt2Img.style.display != "none") {
|
99 |
+
gradioApp().getElementById(saveTxt2Img).click()
|
100 |
+
} else if (tabImg2Img.style.display != "none") {
|
101 |
+
gradioApp().getElementById(saveImg2Img).click()
|
102 |
+
} else {
|
103 |
+
console.error("missing implementation for saving modal of this type")
|
104 |
+
}
|
105 |
+
}
|
106 |
+
|
107 |
+
function modalSaveImage(event) {
|
108 |
+
saveImage()
|
109 |
+
event.stopPropagation()
|
110 |
+
}
|
111 |
+
|
112 |
+
function modalNextImage(event) {
|
113 |
+
modalImageSwitch(1)
|
114 |
+
event.stopPropagation()
|
115 |
+
}
|
116 |
+
|
117 |
+
function modalPrevImage(event) {
|
118 |
+
modalImageSwitch(-1)
|
119 |
+
event.stopPropagation()
|
120 |
+
}
|
121 |
+
|
122 |
+
function modalKeyHandler(event) {
|
123 |
+
switch (event.key) {
|
124 |
+
case "s":
|
125 |
+
saveImage()
|
126 |
+
break;
|
127 |
+
case "ArrowLeft":
|
128 |
+
modalPrevImage(event)
|
129 |
+
break;
|
130 |
+
case "ArrowRight":
|
131 |
+
modalNextImage(event)
|
132 |
+
break;
|
133 |
+
case "Escape":
|
134 |
+
closeModal();
|
135 |
+
break;
|
136 |
+
}
|
137 |
+
}
|
138 |
+
|
139 |
+
function showGalleryImage() {
|
140 |
+
setTimeout(function() {
|
141 |
+
fullImg_preview = gradioApp().querySelectorAll('img.w-full.object-contain')
|
142 |
+
|
143 |
+
if (fullImg_preview != null) {
|
144 |
+
fullImg_preview.forEach(function function_name(e) {
|
145 |
+
if (e.dataset.modded)
|
146 |
+
return;
|
147 |
+
e.dataset.modded = true;
|
148 |
+
if(e && e.parentElement.tagName == 'DIV'){
|
149 |
+
e.style.cursor='pointer'
|
150 |
+
e.style.userSelect='none'
|
151 |
+
e.addEventListener('click', function (evt) {
|
152 |
+
if(!opts.js_modal_lightbox) return;
|
153 |
+
modalZoomSet(gradioApp().getElementById('modalImage'), opts.js_modal_lightbox_initially_zoomed)
|
154 |
+
showModal(evt)
|
155 |
+
}, true);
|
156 |
+
}
|
157 |
+
});
|
158 |
+
}
|
159 |
+
|
160 |
+
}, 100);
|
161 |
+
}
|
162 |
+
|
163 |
+
function modalZoomSet(modalImage, enable) {
|
164 |
+
if (enable) {
|
165 |
+
modalImage.classList.add('modalImageFullscreen');
|
166 |
+
} else {
|
167 |
+
modalImage.classList.remove('modalImageFullscreen');
|
168 |
+
}
|
169 |
+
}
|
170 |
+
|
171 |
+
function modalZoomToggle(event) {
|
172 |
+
modalImage = gradioApp().getElementById("modalImage");
|
173 |
+
modalZoomSet(modalImage, !modalImage.classList.contains('modalImageFullscreen'))
|
174 |
+
event.stopPropagation()
|
175 |
+
}
|
176 |
+
|
177 |
+
function modalTileImageToggle(event) {
|
178 |
+
const modalImage = gradioApp().getElementById("modalImage");
|
179 |
+
const modal = gradioApp().getElementById("lightboxModal");
|
180 |
+
const isTiling = modalImage.style.display === 'none';
|
181 |
+
if (isTiling) {
|
182 |
+
modalImage.style.display = 'block';
|
183 |
+
modal.style.setProperty('background-image', 'none')
|
184 |
+
} else {
|
185 |
+
modalImage.style.display = 'none';
|
186 |
+
modal.style.setProperty('background-image', `url(${modalImage.src})`)
|
187 |
+
}
|
188 |
+
|
189 |
+
event.stopPropagation()
|
190 |
+
}
|
191 |
+
|
192 |
+
function galleryImageHandler(e) {
|
193 |
+
if (e && e.parentElement.tagName == 'BUTTON') {
|
194 |
+
e.onclick = showGalleryImage;
|
195 |
+
}
|
196 |
+
}
|
197 |
+
|
198 |
+
onUiUpdate(function() {
|
199 |
+
fullImg_preview = gradioApp().querySelectorAll('img.w-full')
|
200 |
+
if (fullImg_preview != null) {
|
201 |
+
fullImg_preview.forEach(galleryImageHandler);
|
202 |
+
}
|
203 |
+
updateOnBackgroundChange();
|
204 |
+
})
|
205 |
+
|
206 |
+
document.addEventListener("DOMContentLoaded", function() {
|
207 |
+
const modalFragment = document.createDocumentFragment();
|
208 |
+
const modal = document.createElement('div')
|
209 |
+
modal.onclick = closeModal;
|
210 |
+
modal.id = "lightboxModal";
|
211 |
+
modal.tabIndex = 0
|
212 |
+
modal.addEventListener('keydown', modalKeyHandler, true)
|
213 |
+
|
214 |
+
const modalControls = document.createElement('div')
|
215 |
+
modalControls.className = 'modalControls gradio-container';
|
216 |
+
modal.append(modalControls);
|
217 |
+
|
218 |
+
const modalZoom = document.createElement('span')
|
219 |
+
modalZoom.className = 'modalZoom cursor';
|
220 |
+
modalZoom.innerHTML = '⤡'
|
221 |
+
modalZoom.addEventListener('click', modalZoomToggle, true)
|
222 |
+
modalZoom.title = "Toggle zoomed view";
|
223 |
+
modalControls.appendChild(modalZoom)
|
224 |
+
|
225 |
+
const modalTileImage = document.createElement('span')
|
226 |
+
modalTileImage.className = 'modalTileImage cursor';
|
227 |
+
modalTileImage.innerHTML = '⊞'
|
228 |
+
modalTileImage.addEventListener('click', modalTileImageToggle, true)
|
229 |
+
modalTileImage.title = "Preview tiling";
|
230 |
+
modalControls.appendChild(modalTileImage)
|
231 |
+
|
232 |
+
const modalSave = document.createElement("span")
|
233 |
+
modalSave.className = "modalSave cursor"
|
234 |
+
modalSave.id = "modal_save"
|
235 |
+
modalSave.innerHTML = "🖫"
|
236 |
+
modalSave.addEventListener("click", modalSaveImage, true)
|
237 |
+
modalSave.title = "Save Image(s)"
|
238 |
+
modalControls.appendChild(modalSave)
|
239 |
+
|
240 |
+
const modalClose = document.createElement('span')
|
241 |
+
modalClose.className = 'modalClose cursor';
|
242 |
+
modalClose.innerHTML = '×'
|
243 |
+
modalClose.onclick = closeModal;
|
244 |
+
modalClose.title = "Close image viewer";
|
245 |
+
modalControls.appendChild(modalClose)
|
246 |
+
|
247 |
+
const modalImage = document.createElement('img')
|
248 |
+
modalImage.id = 'modalImage';
|
249 |
+
modalImage.onclick = closeModal;
|
250 |
+
modalImage.tabIndex = 0
|
251 |
+
modalImage.addEventListener('keydown', modalKeyHandler, true)
|
252 |
+
modal.appendChild(modalImage)
|
253 |
+
|
254 |
+
const modalPrev = document.createElement('a')
|
255 |
+
modalPrev.className = 'modalPrev';
|
256 |
+
modalPrev.innerHTML = '❮'
|
257 |
+
modalPrev.tabIndex = 0
|
258 |
+
modalPrev.addEventListener('click', modalPrevImage, true);
|
259 |
+
modalPrev.addEventListener('keydown', modalKeyHandler, true)
|
260 |
+
modal.appendChild(modalPrev)
|
261 |
+
|
262 |
+
const modalNext = document.createElement('a')
|
263 |
+
modalNext.className = 'modalNext';
|
264 |
+
modalNext.innerHTML = '❯'
|
265 |
+
modalNext.tabIndex = 0
|
266 |
+
modalNext.addEventListener('click', modalNextImage, true);
|
267 |
+
modalNext.addEventListener('keydown', modalKeyHandler, true)
|
268 |
+
|
269 |
+
modal.appendChild(modalNext)
|
270 |
+
|
271 |
+
|
272 |
+
gradioApp().getRootNode().appendChild(modal)
|
273 |
+
|
274 |
+
document.body.appendChild(modalFragment);
|
275 |
+
|
276 |
+
});
|
stable-diffusion-webui-master/javascript/localization.js
ADDED
@@ -0,0 +1,167 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
// localization = {} -- the dict with translations is created by the backend
|
3 |
+
|
4 |
+
ignore_ids_for_localization={
|
5 |
+
setting_sd_hypernetwork: 'OPTION',
|
6 |
+
setting_sd_model_checkpoint: 'OPTION',
|
7 |
+
setting_realesrgan_enabled_models: 'OPTION',
|
8 |
+
modelmerger_primary_model_name: 'OPTION',
|
9 |
+
modelmerger_secondary_model_name: 'OPTION',
|
10 |
+
modelmerger_tertiary_model_name: 'OPTION',
|
11 |
+
train_embedding: 'OPTION',
|
12 |
+
train_hypernetwork: 'OPTION',
|
13 |
+
txt2img_style_index: 'OPTION',
|
14 |
+
txt2img_style2_index: 'OPTION',
|
15 |
+
img2img_style_index: 'OPTION',
|
16 |
+
img2img_style2_index: 'OPTION',
|
17 |
+
setting_random_artist_categories: 'SPAN',
|
18 |
+
setting_face_restoration_model: 'SPAN',
|
19 |
+
setting_realesrgan_enabled_models: 'SPAN',
|
20 |
+
extras_upscaler_1: 'SPAN',
|
21 |
+
extras_upscaler_2: 'SPAN',
|
22 |
+
}
|
23 |
+
|
24 |
+
re_num = /^[\.\d]+$/
|
25 |
+
re_emoji = /[\p{Extended_Pictographic}\u{1F3FB}-\u{1F3FF}\u{1F9B0}-\u{1F9B3}]/u
|
26 |
+
|
27 |
+
original_lines = {}
|
28 |
+
translated_lines = {}
|
29 |
+
|
30 |
+
function textNodesUnder(el){
|
31 |
+
var n, a=[], walk=document.createTreeWalker(el,NodeFilter.SHOW_TEXT,null,false);
|
32 |
+
while(n=walk.nextNode()) a.push(n);
|
33 |
+
return a;
|
34 |
+
}
|
35 |
+
|
36 |
+
function canBeTranslated(node, text){
|
37 |
+
if(! text) return false;
|
38 |
+
if(! node.parentElement) return false;
|
39 |
+
|
40 |
+
parentType = node.parentElement.nodeName
|
41 |
+
if(parentType=='SCRIPT' || parentType=='STYLE' || parentType=='TEXTAREA') return false;
|
42 |
+
|
43 |
+
if (parentType=='OPTION' || parentType=='SPAN'){
|
44 |
+
pnode = node
|
45 |
+
for(var level=0; level<4; level++){
|
46 |
+
pnode = pnode.parentElement
|
47 |
+
if(! pnode) break;
|
48 |
+
|
49 |
+
if(ignore_ids_for_localization[pnode.id] == parentType) return false;
|
50 |
+
}
|
51 |
+
}
|
52 |
+
|
53 |
+
if(re_num.test(text)) return false;
|
54 |
+
if(re_emoji.test(text)) return false;
|
55 |
+
return true
|
56 |
+
}
|
57 |
+
|
58 |
+
function getTranslation(text){
|
59 |
+
if(! text) return undefined
|
60 |
+
|
61 |
+
if(translated_lines[text] === undefined){
|
62 |
+
original_lines[text] = 1
|
63 |
+
}
|
64 |
+
|
65 |
+
tl = localization[text]
|
66 |
+
if(tl !== undefined){
|
67 |
+
translated_lines[tl] = 1
|
68 |
+
}
|
69 |
+
|
70 |
+
return tl
|
71 |
+
}
|
72 |
+
|
73 |
+
function processTextNode(node){
|
74 |
+
text = node.textContent.trim()
|
75 |
+
|
76 |
+
if(! canBeTranslated(node, text)) return
|
77 |
+
|
78 |
+
tl = getTranslation(text)
|
79 |
+
if(tl !== undefined){
|
80 |
+
node.textContent = tl
|
81 |
+
}
|
82 |
+
}
|
83 |
+
|
84 |
+
function processNode(node){
|
85 |
+
if(node.nodeType == 3){
|
86 |
+
processTextNode(node)
|
87 |
+
return
|
88 |
+
}
|
89 |
+
|
90 |
+
if(node.title){
|
91 |
+
tl = getTranslation(node.title)
|
92 |
+
if(tl !== undefined){
|
93 |
+
node.title = tl
|
94 |
+
}
|
95 |
+
}
|
96 |
+
|
97 |
+
if(node.placeholder){
|
98 |
+
tl = getTranslation(node.placeholder)
|
99 |
+
if(tl !== undefined){
|
100 |
+
node.placeholder = tl
|
101 |
+
}
|
102 |
+
}
|
103 |
+
|
104 |
+
textNodesUnder(node).forEach(function(node){
|
105 |
+
processTextNode(node)
|
106 |
+
})
|
107 |
+
}
|
108 |
+
|
109 |
+
function dumpTranslations(){
|
110 |
+
dumped = {}
|
111 |
+
if (localization.rtl) {
|
112 |
+
dumped.rtl = true
|
113 |
+
}
|
114 |
+
|
115 |
+
Object.keys(original_lines).forEach(function(text){
|
116 |
+
if(dumped[text] !== undefined) return
|
117 |
+
|
118 |
+
dumped[text] = localization[text] || text
|
119 |
+
})
|
120 |
+
|
121 |
+
return dumped
|
122 |
+
}
|
123 |
+
|
124 |
+
onUiUpdate(function(m){
|
125 |
+
m.forEach(function(mutation){
|
126 |
+
mutation.addedNodes.forEach(function(node){
|
127 |
+
processNode(node)
|
128 |
+
})
|
129 |
+
});
|
130 |
+
})
|
131 |
+
|
132 |
+
|
133 |
+
document.addEventListener("DOMContentLoaded", function() {
|
134 |
+
processNode(gradioApp())
|
135 |
+
|
136 |
+
if (localization.rtl) { // if the language is from right to left,
|
137 |
+
(new MutationObserver((mutations, observer) => { // wait for the style to load
|
138 |
+
mutations.forEach(mutation => {
|
139 |
+
mutation.addedNodes.forEach(node => {
|
140 |
+
if (node.tagName === 'STYLE') {
|
141 |
+
observer.disconnect();
|
142 |
+
|
143 |
+
for (const x of node.sheet.rules) { // find all rtl media rules
|
144 |
+
if (Array.from(x.media || []).includes('rtl')) {
|
145 |
+
x.media.appendMedium('all'); // enable them
|
146 |
+
}
|
147 |
+
}
|
148 |
+
}
|
149 |
+
})
|
150 |
+
});
|
151 |
+
})).observe(gradioApp(), { childList: true });
|
152 |
+
}
|
153 |
+
})
|
154 |
+
|
155 |
+
function download_localization() {
|
156 |
+
text = JSON.stringify(dumpTranslations(), null, 4)
|
157 |
+
|
158 |
+
var element = document.createElement('a');
|
159 |
+
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
|
160 |
+
element.setAttribute('download', "localization.json");
|
161 |
+
element.style.display = 'none';
|
162 |
+
document.body.appendChild(element);
|
163 |
+
|
164 |
+
element.click();
|
165 |
+
|
166 |
+
document.body.removeChild(element);
|
167 |
+
}
|
stable-diffusion-webui-master/javascript/notification.js
ADDED
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
// Monitors the gallery and sends a browser notification when the leading image is new.
|
2 |
+
|
3 |
+
let lastHeadImg = null;
|
4 |
+
|
5 |
+
notificationButton = null
|
6 |
+
|
7 |
+
onUiUpdate(function(){
|
8 |
+
if(notificationButton == null){
|
9 |
+
notificationButton = gradioApp().getElementById('request_notifications')
|
10 |
+
|
11 |
+
if(notificationButton != null){
|
12 |
+
notificationButton.addEventListener('click', function (evt) {
|
13 |
+
Notification.requestPermission();
|
14 |
+
},true);
|
15 |
+
}
|
16 |
+
}
|
17 |
+
|
18 |
+
const galleryPreviews = gradioApp().querySelectorAll('img.h-full.w-full.overflow-hidden');
|
19 |
+
|
20 |
+
if (galleryPreviews == null) return;
|
21 |
+
|
22 |
+
const headImg = galleryPreviews[0]?.src;
|
23 |
+
|
24 |
+
if (headImg == null || headImg == lastHeadImg) return;
|
25 |
+
|
26 |
+
lastHeadImg = headImg;
|
27 |
+
|
28 |
+
// play notification sound if available
|
29 |
+
gradioApp().querySelector('#audio_notification audio')?.play();
|
30 |
+
|
31 |
+
if (document.hasFocus()) return;
|
32 |
+
|
33 |
+
// Multiple copies of the images are in the DOM when one is selected. Dedup with a Set to get the real number generated.
|
34 |
+
const imgs = new Set(Array.from(galleryPreviews).map(img => img.src));
|
35 |
+
|
36 |
+
const notification = new Notification(
|
37 |
+
'Stable Diffusion',
|
38 |
+
{
|
39 |
+
body: `Generated ${imgs.size > 1 ? imgs.size - opts.return_grid : 1} image${imgs.size > 1 ? 's' : ''}`,
|
40 |
+
icon: headImg,
|
41 |
+
image: headImg,
|
42 |
+
}
|
43 |
+
);
|
44 |
+
|
45 |
+
notification.onclick = function(_){
|
46 |
+
parent.focus();
|
47 |
+
this.close();
|
48 |
+
};
|
49 |
+
});
|
stable-diffusion-webui-master/javascript/progressbar.js
ADDED
@@ -0,0 +1,137 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
// code related to showing and updating progressbar shown as the image is being made
|
2 |
+
global_progressbars = {}
|
3 |
+
galleries = {}
|
4 |
+
galleryObservers = {}
|
5 |
+
|
6 |
+
// this tracks laumnches of window.setTimeout for progressbar to prevent starting a new timeout when the previous is still running
|
7 |
+
timeoutIds = {}
|
8 |
+
|
9 |
+
function check_progressbar(id_part, id_progressbar, id_progressbar_span, id_skip, id_interrupt, id_preview, id_gallery){
|
10 |
+
// gradio 3.8's enlightened approach allows them to create two nested div elements inside each other with same id
|
11 |
+
// every time you use gr.HTML(elem_id='xxx'), so we handle this here
|
12 |
+
var progressbar = gradioApp().querySelector("#"+id_progressbar+" #"+id_progressbar)
|
13 |
+
var progressbarParent
|
14 |
+
if(progressbar){
|
15 |
+
progressbarParent = gradioApp().querySelector("#"+id_progressbar)
|
16 |
+
} else{
|
17 |
+
progressbar = gradioApp().getElementById(id_progressbar)
|
18 |
+
progressbarParent = null
|
19 |
+
}
|
20 |
+
|
21 |
+
var skip = id_skip ? gradioApp().getElementById(id_skip) : null
|
22 |
+
var interrupt = gradioApp().getElementById(id_interrupt)
|
23 |
+
|
24 |
+
if(opts.show_progress_in_title && progressbar && progressbar.offsetParent){
|
25 |
+
if(progressbar.innerText){
|
26 |
+
let newtitle = '[' + progressbar.innerText.trim() + '] Stable Diffusion';
|
27 |
+
if(document.title != newtitle){
|
28 |
+
document.title = newtitle;
|
29 |
+
}
|
30 |
+
}else{
|
31 |
+
let newtitle = 'Stable Diffusion'
|
32 |
+
if(document.title != newtitle){
|
33 |
+
document.title = newtitle;
|
34 |
+
}
|
35 |
+
}
|
36 |
+
}
|
37 |
+
|
38 |
+
if(progressbar!= null && progressbar != global_progressbars[id_progressbar]){
|
39 |
+
global_progressbars[id_progressbar] = progressbar
|
40 |
+
|
41 |
+
var mutationObserver = new MutationObserver(function(m){
|
42 |
+
if(timeoutIds[id_part]) return;
|
43 |
+
|
44 |
+
preview = gradioApp().getElementById(id_preview)
|
45 |
+
gallery = gradioApp().getElementById(id_gallery)
|
46 |
+
|
47 |
+
if(preview != null && gallery != null){
|
48 |
+
preview.style.width = gallery.clientWidth + "px"
|
49 |
+
preview.style.height = gallery.clientHeight + "px"
|
50 |
+
if(progressbarParent) progressbar.style.width = progressbarParent.clientWidth + "px"
|
51 |
+
|
52 |
+
//only watch gallery if there is a generation process going on
|
53 |
+
check_gallery(id_gallery);
|
54 |
+
|
55 |
+
var progressDiv = gradioApp().querySelectorAll('#' + id_progressbar_span).length > 0;
|
56 |
+
if(progressDiv){
|
57 |
+
timeoutIds[id_part] = window.setTimeout(function() {
|
58 |
+
timeoutIds[id_part] = null
|
59 |
+
requestMoreProgress(id_part, id_progressbar_span, id_skip, id_interrupt)
|
60 |
+
}, 500)
|
61 |
+
} else{
|
62 |
+
if (skip) {
|
63 |
+
skip.style.display = "none"
|
64 |
+
}
|
65 |
+
interrupt.style.display = "none"
|
66 |
+
|
67 |
+
//disconnect observer once generation finished, so user can close selected image if they want
|
68 |
+
if (galleryObservers[id_gallery]) {
|
69 |
+
galleryObservers[id_gallery].disconnect();
|
70 |
+
galleries[id_gallery] = null;
|
71 |
+
}
|
72 |
+
}
|
73 |
+
}
|
74 |
+
|
75 |
+
});
|
76 |
+
mutationObserver.observe( progressbar, { childList:true, subtree:true })
|
77 |
+
}
|
78 |
+
}
|
79 |
+
|
80 |
+
function check_gallery(id_gallery){
|
81 |
+
let gallery = gradioApp().getElementById(id_gallery)
|
82 |
+
// if gallery has no change, no need to setting up observer again.
|
83 |
+
if (gallery && galleries[id_gallery] !== gallery){
|
84 |
+
galleries[id_gallery] = gallery;
|
85 |
+
if(galleryObservers[id_gallery]){
|
86 |
+
galleryObservers[id_gallery].disconnect();
|
87 |
+
}
|
88 |
+
let prevSelectedIndex = selected_gallery_index();
|
89 |
+
galleryObservers[id_gallery] = new MutationObserver(function (){
|
90 |
+
let galleryButtons = gradioApp().querySelectorAll('#'+id_gallery+' .gallery-item')
|
91 |
+
let galleryBtnSelected = gradioApp().querySelector('#'+id_gallery+' .gallery-item.\\!ring-2')
|
92 |
+
if (prevSelectedIndex !== -1 && galleryButtons.length>prevSelectedIndex && !galleryBtnSelected) {
|
93 |
+
// automatically re-open previously selected index (if exists)
|
94 |
+
activeElement = gradioApp().activeElement;
|
95 |
+
|
96 |
+
galleryButtons[prevSelectedIndex].click();
|
97 |
+
showGalleryImage();
|
98 |
+
|
99 |
+
if(activeElement){
|
100 |
+
// i fought this for about an hour; i don't know why the focus is lost or why this helps recover it
|
101 |
+
// if somenoe has a better solution please by all means
|
102 |
+
setTimeout(function() { activeElement.focus() }, 1);
|
103 |
+
}
|
104 |
+
}
|
105 |
+
})
|
106 |
+
galleryObservers[id_gallery].observe( gallery, { childList:true, subtree:false })
|
107 |
+
}
|
108 |
+
}
|
109 |
+
|
110 |
+
onUiUpdate(function(){
|
111 |
+
check_progressbar('txt2img', 'txt2img_progressbar', 'txt2img_progress_span', 'txt2img_skip', 'txt2img_interrupt', 'txt2img_preview', 'txt2img_gallery')
|
112 |
+
check_progressbar('img2img', 'img2img_progressbar', 'img2img_progress_span', 'img2img_skip', 'img2img_interrupt', 'img2img_preview', 'img2img_gallery')
|
113 |
+
check_progressbar('ti', 'ti_progressbar', 'ti_progress_span', '', 'ti_interrupt', 'ti_preview', 'ti_gallery')
|
114 |
+
})
|
115 |
+
|
116 |
+
function requestMoreProgress(id_part, id_progressbar_span, id_skip, id_interrupt){
|
117 |
+
btn = gradioApp().getElementById(id_part+"_check_progress");
|
118 |
+
if(btn==null) return;
|
119 |
+
|
120 |
+
btn.click();
|
121 |
+
var progressDiv = gradioApp().querySelectorAll('#' + id_progressbar_span).length > 0;
|
122 |
+
var skip = id_skip ? gradioApp().getElementById(id_skip) : null
|
123 |
+
var interrupt = gradioApp().getElementById(id_interrupt)
|
124 |
+
if(progressDiv && interrupt){
|
125 |
+
if (skip) {
|
126 |
+
skip.style.display = "block"
|
127 |
+
}
|
128 |
+
interrupt.style.display = "block"
|
129 |
+
}
|
130 |
+
}
|
131 |
+
|
132 |
+
function requestProgress(id_part){
|
133 |
+
btn = gradioApp().getElementById(id_part+"_check_progress_initial");
|
134 |
+
if(btn==null) return;
|
135 |
+
|
136 |
+
btn.click();
|
137 |
+
}
|
stable-diffusion-webui-master/javascript/textualInversion.js
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
|
3 |
+
function start_training_textual_inversion(){
|
4 |
+
requestProgress('ti')
|
5 |
+
gradioApp().querySelector('#ti_error').innerHTML=''
|
6 |
+
|
7 |
+
return args_to_array(arguments)
|
8 |
+
}
|
stable-diffusion-webui-master/javascript/ui.js
ADDED
@@ -0,0 +1,213 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
// various functions for interation with ui.py not large enough to warrant putting them in separate files
|
2 |
+
|
3 |
+
function set_theme(theme){
|
4 |
+
gradioURL = window.location.href
|
5 |
+
if (!gradioURL.includes('?__theme=')) {
|
6 |
+
window.location.replace(gradioURL + '?__theme=' + theme);
|
7 |
+
}
|
8 |
+
}
|
9 |
+
|
10 |
+
function selected_gallery_index(){
|
11 |
+
var buttons = gradioApp().querySelectorAll('[style="display: block;"].tabitem div[id$=_gallery] .gallery-item')
|
12 |
+
var button = gradioApp().querySelector('[style="display: block;"].tabitem div[id$=_gallery] .gallery-item.\\!ring-2')
|
13 |
+
|
14 |
+
var result = -1
|
15 |
+
buttons.forEach(function(v, i){ if(v==button) { result = i } })
|
16 |
+
|
17 |
+
return result
|
18 |
+
}
|
19 |
+
|
20 |
+
function extract_image_from_gallery(gallery){
|
21 |
+
if(gallery.length == 1){
|
22 |
+
return gallery[0]
|
23 |
+
}
|
24 |
+
|
25 |
+
index = selected_gallery_index()
|
26 |
+
|
27 |
+
if (index < 0 || index >= gallery.length){
|
28 |
+
return [null]
|
29 |
+
}
|
30 |
+
|
31 |
+
return gallery[index];
|
32 |
+
}
|
33 |
+
|
34 |
+
function args_to_array(args){
|
35 |
+
res = []
|
36 |
+
for(var i=0;i<args.length;i++){
|
37 |
+
res.push(args[i])
|
38 |
+
}
|
39 |
+
return res
|
40 |
+
}
|
41 |
+
|
42 |
+
function switch_to_txt2img(){
|
43 |
+
gradioApp().querySelector('#tabs').querySelectorAll('button')[0].click();
|
44 |
+
|
45 |
+
return args_to_array(arguments);
|
46 |
+
}
|
47 |
+
|
48 |
+
function switch_to_img2img(){
|
49 |
+
gradioApp().querySelector('#tabs').querySelectorAll('button')[1].click();
|
50 |
+
gradioApp().getElementById('mode_img2img').querySelectorAll('button')[0].click();
|
51 |
+
|
52 |
+
return args_to_array(arguments);
|
53 |
+
}
|
54 |
+
|
55 |
+
function switch_to_inpaint(){
|
56 |
+
gradioApp().querySelector('#tabs').querySelectorAll('button')[1].click();
|
57 |
+
gradioApp().getElementById('mode_img2img').querySelectorAll('button')[1].click();
|
58 |
+
|
59 |
+
return args_to_array(arguments);
|
60 |
+
}
|
61 |
+
|
62 |
+
function switch_to_extras(){
|
63 |
+
gradioApp().querySelector('#tabs').querySelectorAll('button')[2].click();
|
64 |
+
|
65 |
+
return args_to_array(arguments);
|
66 |
+
}
|
67 |
+
|
68 |
+
function get_tab_index(tabId){
|
69 |
+
var res = 0
|
70 |
+
|
71 |
+
gradioApp().getElementById(tabId).querySelector('div').querySelectorAll('button').forEach(function(button, i){
|
72 |
+
if(button.className.indexOf('bg-white') != -1)
|
73 |
+
res = i
|
74 |
+
})
|
75 |
+
|
76 |
+
return res
|
77 |
+
}
|
78 |
+
|
79 |
+
function create_tab_index_args(tabId, args){
|
80 |
+
var res = []
|
81 |
+
for(var i=0; i<args.length; i++){
|
82 |
+
res.push(args[i])
|
83 |
+
}
|
84 |
+
|
85 |
+
res[0] = get_tab_index(tabId)
|
86 |
+
|
87 |
+
return res
|
88 |
+
}
|
89 |
+
|
90 |
+
function get_extras_tab_index(){
|
91 |
+
const [,,...args] = [...arguments]
|
92 |
+
return [get_tab_index('mode_extras'), get_tab_index('extras_resize_mode'), ...args]
|
93 |
+
}
|
94 |
+
|
95 |
+
function create_submit_args(args){
|
96 |
+
res = []
|
97 |
+
for(var i=0;i<args.length;i++){
|
98 |
+
res.push(args[i])
|
99 |
+
}
|
100 |
+
|
101 |
+
// As it is currently, txt2img and img2img send back the previous output args (txt2img_gallery, generation_info, html_info) whenever you generate a new image.
|
102 |
+
// This can lead to uploading a huge gallery of previously generated images, which leads to an unnecessary delay between submitting and beginning to generate.
|
103 |
+
// I don't know why gradio is seding outputs along with inputs, but we can prevent sending the image gallery here, which seems to be an issue for some.
|
104 |
+
// If gradio at some point stops sending outputs, this may break something
|
105 |
+
if(Array.isArray(res[res.length - 3])){
|
106 |
+
res[res.length - 3] = null
|
107 |
+
}
|
108 |
+
|
109 |
+
return res
|
110 |
+
}
|
111 |
+
|
112 |
+
function submit(){
|
113 |
+
requestProgress('txt2img')
|
114 |
+
|
115 |
+
return create_submit_args(arguments)
|
116 |
+
}
|
117 |
+
|
118 |
+
function submit_img2img(){
|
119 |
+
requestProgress('img2img')
|
120 |
+
|
121 |
+
res = create_submit_args(arguments)
|
122 |
+
|
123 |
+
res[0] = get_tab_index('mode_img2img')
|
124 |
+
|
125 |
+
return res
|
126 |
+
}
|
127 |
+
|
128 |
+
|
129 |
+
function ask_for_style_name(_, prompt_text, negative_prompt_text) {
|
130 |
+
name_ = prompt('Style name:')
|
131 |
+
return [name_, prompt_text, negative_prompt_text]
|
132 |
+
}
|
133 |
+
|
134 |
+
|
135 |
+
|
136 |
+
opts = {}
|
137 |
+
function apply_settings(jsdata){
|
138 |
+
console.log(jsdata)
|
139 |
+
|
140 |
+
opts = JSON.parse(jsdata)
|
141 |
+
|
142 |
+
return jsdata
|
143 |
+
}
|
144 |
+
|
145 |
+
onUiUpdate(function(){
|
146 |
+
if(Object.keys(opts).length != 0) return;
|
147 |
+
|
148 |
+
json_elem = gradioApp().getElementById('settings_json')
|
149 |
+
if(json_elem == null) return;
|
150 |
+
|
151 |
+
textarea = json_elem.querySelector('textarea')
|
152 |
+
jsdata = textarea.value
|
153 |
+
opts = JSON.parse(jsdata)
|
154 |
+
|
155 |
+
|
156 |
+
Object.defineProperty(textarea, 'value', {
|
157 |
+
set: function(newValue) {
|
158 |
+
var valueProp = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, 'value');
|
159 |
+
var oldValue = valueProp.get.call(textarea);
|
160 |
+
valueProp.set.call(textarea, newValue);
|
161 |
+
|
162 |
+
if (oldValue != newValue) {
|
163 |
+
opts = JSON.parse(textarea.value)
|
164 |
+
}
|
165 |
+
},
|
166 |
+
get: function() {
|
167 |
+
var valueProp = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, 'value');
|
168 |
+
return valueProp.get.call(textarea);
|
169 |
+
}
|
170 |
+
});
|
171 |
+
|
172 |
+
json_elem.parentElement.style.display="none"
|
173 |
+
|
174 |
+
if (!txt2img_textarea) {
|
175 |
+
txt2img_textarea = gradioApp().querySelector("#txt2img_prompt > label > textarea");
|
176 |
+
txt2img_textarea?.addEventListener("input", () => update_token_counter("txt2img_token_button"));
|
177 |
+
}
|
178 |
+
if (!img2img_textarea) {
|
179 |
+
img2img_textarea = gradioApp().querySelector("#img2img_prompt > label > textarea");
|
180 |
+
img2img_textarea?.addEventListener("input", () => update_token_counter("img2img_token_button"));
|
181 |
+
}
|
182 |
+
})
|
183 |
+
|
184 |
+
let txt2img_textarea, img2img_textarea = undefined;
|
185 |
+
let wait_time = 800
|
186 |
+
let token_timeout;
|
187 |
+
|
188 |
+
function update_txt2img_tokens(...args) {
|
189 |
+
update_token_counter("txt2img_token_button")
|
190 |
+
if (args.length == 2)
|
191 |
+
return args[0]
|
192 |
+
return args;
|
193 |
+
}
|
194 |
+
|
195 |
+
function update_img2img_tokens(...args) {
|
196 |
+
update_token_counter("img2img_token_button")
|
197 |
+
if (args.length == 2)
|
198 |
+
return args[0]
|
199 |
+
return args;
|
200 |
+
}
|
201 |
+
|
202 |
+
function update_token_counter(button_id) {
|
203 |
+
if (token_timeout)
|
204 |
+
clearTimeout(token_timeout);
|
205 |
+
token_timeout = setTimeout(() => gradioApp().getElementById(button_id)?.click(), wait_time);
|
206 |
+
}
|
207 |
+
|
208 |
+
function restart_reload(){
|
209 |
+
document.body.innerHTML='<h1 style="font-family:monospace;margin-top:20%;color:lightgray;text-align:center;">Reloading...</h1>';
|
210 |
+
setTimeout(function(){location.reload()},2000)
|
211 |
+
|
212 |
+
return []
|
213 |
+
}
|
stable-diffusion-webui-master/launch.py
ADDED
@@ -0,0 +1,294 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# this scripts installs necessary requirements and launches main program in webui.py
|
2 |
+
import subprocess
|
3 |
+
import os
|
4 |
+
import sys
|
5 |
+
import importlib.util
|
6 |
+
import shlex
|
7 |
+
import platform
|
8 |
+
import argparse
|
9 |
+
import json
|
10 |
+
|
11 |
+
dir_repos = "repositories"
|
12 |
+
dir_extensions = "extensions"
|
13 |
+
python = sys.executable
|
14 |
+
git = os.environ.get('GIT', "git")
|
15 |
+
index_url = os.environ.get('INDEX_URL', "")
|
16 |
+
|
17 |
+
|
18 |
+
def extract_arg(args, name):
|
19 |
+
return [x for x in args if x != name], name in args
|
20 |
+
|
21 |
+
|
22 |
+
def extract_opt(args, name):
|
23 |
+
opt = None
|
24 |
+
is_present = False
|
25 |
+
if name in args:
|
26 |
+
is_present = True
|
27 |
+
idx = args.index(name)
|
28 |
+
del args[idx]
|
29 |
+
if idx < len(args) and args[idx][0] != "-":
|
30 |
+
opt = args[idx]
|
31 |
+
del args[idx]
|
32 |
+
return args, is_present, opt
|
33 |
+
|
34 |
+
|
35 |
+
def run(command, desc=None, errdesc=None, custom_env=None):
|
36 |
+
if desc is not None:
|
37 |
+
print(desc)
|
38 |
+
|
39 |
+
result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, env=os.environ if custom_env is None else custom_env)
|
40 |
+
|
41 |
+
if result.returncode != 0:
|
42 |
+
|
43 |
+
message = f"""{errdesc or 'Error running command'}.
|
44 |
+
Command: {command}
|
45 |
+
Error code: {result.returncode}
|
46 |
+
stdout: {result.stdout.decode(encoding="utf8", errors="ignore") if len(result.stdout)>0 else '<empty>'}
|
47 |
+
stderr: {result.stderr.decode(encoding="utf8", errors="ignore") if len(result.stderr)>0 else '<empty>'}
|
48 |
+
"""
|
49 |
+
raise RuntimeError(message)
|
50 |
+
|
51 |
+
return result.stdout.decode(encoding="utf8", errors="ignore")
|
52 |
+
|
53 |
+
|
54 |
+
def check_run(command):
|
55 |
+
result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
|
56 |
+
return result.returncode == 0
|
57 |
+
|
58 |
+
|
59 |
+
def is_installed(package):
|
60 |
+
try:
|
61 |
+
spec = importlib.util.find_spec(package)
|
62 |
+
except ModuleNotFoundError:
|
63 |
+
return False
|
64 |
+
|
65 |
+
return spec is not None
|
66 |
+
|
67 |
+
|
68 |
+
def repo_dir(name):
|
69 |
+
return os.path.join(dir_repos, name)
|
70 |
+
|
71 |
+
|
72 |
+
def run_python(code, desc=None, errdesc=None):
|
73 |
+
return run(f'"{python}" -c "{code}"', desc, errdesc)
|
74 |
+
|
75 |
+
|
76 |
+
def run_pip(args, desc=None):
|
77 |
+
index_url_line = f' --index-url {index_url}' if index_url != '' else ''
|
78 |
+
return run(f'"{python}" -m pip {args} --prefer-binary{index_url_line}', desc=f"Installing {desc}", errdesc=f"Couldn't install {desc}")
|
79 |
+
|
80 |
+
|
81 |
+
def check_run_python(code):
|
82 |
+
return check_run(f'"{python}" -c "{code}"')
|
83 |
+
|
84 |
+
|
85 |
+
def git_clone(url, dir, name, commithash=None):
|
86 |
+
# TODO clone into temporary dir and move if successful
|
87 |
+
|
88 |
+
if os.path.exists(dir):
|
89 |
+
if commithash is None:
|
90 |
+
return
|
91 |
+
|
92 |
+
current_hash = run(f'"{git}" -C {dir} rev-parse HEAD', None, f"Couldn't determine {name}'s hash: {commithash}").strip()
|
93 |
+
if current_hash == commithash:
|
94 |
+
return
|
95 |
+
|
96 |
+
run(f'"{git}" -C {dir} fetch', f"Fetching updates for {name}...", f"Couldn't fetch {name}")
|
97 |
+
run(f'"{git}" -C {dir} checkout {commithash}', f"Checking out commit for {name} with hash: {commithash}...", f"Couldn't checkout commit {commithash} for {name}")
|
98 |
+
return
|
99 |
+
|
100 |
+
run(f'"{git}" clone "{url}" "{dir}"', f"Cloning {name} into {dir}...", f"Couldn't clone {name}")
|
101 |
+
|
102 |
+
if commithash is not None:
|
103 |
+
run(f'"{git}" -C {dir} checkout {commithash}', None, "Couldn't checkout {name}'s hash: {commithash}")
|
104 |
+
|
105 |
+
|
106 |
+
def version_check(commit):
|
107 |
+
try:
|
108 |
+
import requests
|
109 |
+
commits = requests.get('https://api.github.com/repos/AUTOMATIC1111/stable-diffusion-webui/branches/master').json()
|
110 |
+
if commit != "<none>" and commits['commit']['sha'] != commit:
|
111 |
+
print("--------------------------------------------------------")
|
112 |
+
print("| You are not up to date with the most recent release. |")
|
113 |
+
print("| Consider running `git pull` to update. |")
|
114 |
+
print("--------------------------------------------------------")
|
115 |
+
elif commits['commit']['sha'] == commit:
|
116 |
+
print("You are up to date with the most recent release.")
|
117 |
+
else:
|
118 |
+
print("Not a git clone, can't perform version check.")
|
119 |
+
except Exception as e:
|
120 |
+
print("version check failed", e)
|
121 |
+
|
122 |
+
|
123 |
+
def run_extension_installer(extension_dir):
|
124 |
+
path_installer = os.path.join(extension_dir, "install.py")
|
125 |
+
if not os.path.isfile(path_installer):
|
126 |
+
return
|
127 |
+
|
128 |
+
try:
|
129 |
+
env = os.environ.copy()
|
130 |
+
env['PYTHONPATH'] = os.path.abspath(".")
|
131 |
+
|
132 |
+
print(run(f'"{python}" "{path_installer}"', errdesc=f"Error running install.py for extension {extension_dir}", custom_env=env))
|
133 |
+
except Exception as e:
|
134 |
+
print(e, file=sys.stderr)
|
135 |
+
|
136 |
+
|
137 |
+
def list_extensions(settings_file):
|
138 |
+
settings = {}
|
139 |
+
|
140 |
+
try:
|
141 |
+
if os.path.isfile(settings_file):
|
142 |
+
with open(settings_file, "r", encoding="utf8") as file:
|
143 |
+
settings = json.load(file)
|
144 |
+
except Exception as e:
|
145 |
+
print(e, file=sys.stderr)
|
146 |
+
|
147 |
+
disabled_extensions = set(settings.get('disabled_extensions', []))
|
148 |
+
|
149 |
+
return [x for x in os.listdir(dir_extensions) if x not in disabled_extensions]
|
150 |
+
|
151 |
+
|
152 |
+
def run_extensions_installers(settings_file):
|
153 |
+
if not os.path.isdir(dir_extensions):
|
154 |
+
return
|
155 |
+
|
156 |
+
for dirname_extension in list_extensions(settings_file):
|
157 |
+
run_extension_installer(os.path.join(dir_extensions, dirname_extension))
|
158 |
+
|
159 |
+
|
160 |
+
def prepare_enviroment():
|
161 |
+
torch_command = os.environ.get('TORCH_COMMAND', "pip install torch==1.12.1+cu113 torchvision==0.13.1+cu113 --extra-index-url https://download.pytorch.org/whl/cu113")
|
162 |
+
requirements_file = os.environ.get('REQS_FILE', "requirements_versions.txt")
|
163 |
+
commandline_args = os.environ.get('COMMANDLINE_ARGS', "")
|
164 |
+
|
165 |
+
gfpgan_package = os.environ.get('GFPGAN_PACKAGE', "git+https://github.com/TencentARC/GFPGAN.git@8d2447a2d918f8eba5a4a01463fd48e45126a379")
|
166 |
+
clip_package = os.environ.get('CLIP_PACKAGE', "git+https://github.com/openai/CLIP.git@d50d76daa670286dd6cacf3bcd80b5e4823fc8e1")
|
167 |
+
openclip_package = os.environ.get('OPENCLIP_PACKAGE', "git+https://github.com/mlfoundations/open_clip.git@bb6e834e9c70d9c27d0dc3ecedeebeaeb1ffad6b")
|
168 |
+
|
169 |
+
xformers_windows_package = os.environ.get('XFORMERS_WINDOWS_PACKAGE', 'https://github.com/C43H66N12O12S2/stable-diffusion-webui/releases/download/f/xformers-0.0.14.dev0-cp310-cp310-win_amd64.whl')
|
170 |
+
|
171 |
+
stable_diffusion_repo = os.environ.get('STABLE_DIFFUSION_REPO', "https://github.com/Stability-AI/stablediffusion.git")
|
172 |
+
taming_transformers_repo = os.environ.get('TAMING_TRANSFORMERS_REPO', "https://github.com/CompVis/taming-transformers.git")
|
173 |
+
k_diffusion_repo = os.environ.get('K_DIFFUSION_REPO', 'https://github.com/crowsonkb/k-diffusion.git')
|
174 |
+
codeformer_repo = os.environ.get('CODEFORMER_REPO', 'https://github.com/sczhou/CodeFormer.git')
|
175 |
+
blip_repo = os.environ.get('BLIP_REPO', 'https://github.com/salesforce/BLIP.git')
|
176 |
+
|
177 |
+
stable_diffusion_commit_hash = os.environ.get('STABLE_DIFFUSION_COMMIT_HASH', "47b6b607fdd31875c9279cd2f4f16b92e4ea958e")
|
178 |
+
taming_transformers_commit_hash = os.environ.get('TAMING_TRANSFORMERS_COMMIT_HASH', "24268930bf1dce879235a7fddd0b2355b84d7ea6")
|
179 |
+
k_diffusion_commit_hash = os.environ.get('K_DIFFUSION_COMMIT_HASH', "5b3af030dd83e0297272d861c19477735d0317ec")
|
180 |
+
codeformer_commit_hash = os.environ.get('CODEFORMER_COMMIT_HASH', "c5b4593074ba6214284d6acd5f1719b6c5d739af")
|
181 |
+
blip_commit_hash = os.environ.get('BLIP_COMMIT_HASH', "48211a1594f1321b00f14c9f7a5b4813144b2fb9")
|
182 |
+
|
183 |
+
sys.argv += shlex.split(commandline_args)
|
184 |
+
|
185 |
+
parser = argparse.ArgumentParser()
|
186 |
+
parser.add_argument("--ui-settings-file", type=str, help="filename to use for ui settings", default='config.json')
|
187 |
+
args, _ = parser.parse_known_args(sys.argv)
|
188 |
+
|
189 |
+
sys.argv, skip_torch_cuda_test = extract_arg(sys.argv, '--skip-torch-cuda-test')
|
190 |
+
sys.argv, reinstall_xformers = extract_arg(sys.argv, '--reinstall-xformers')
|
191 |
+
sys.argv, update_check = extract_arg(sys.argv, '--update-check')
|
192 |
+
sys.argv, run_tests, test_dir = extract_opt(sys.argv, '--tests')
|
193 |
+
xformers = '--xformers' in sys.argv
|
194 |
+
ngrok = '--ngrok' in sys.argv
|
195 |
+
|
196 |
+
try:
|
197 |
+
commit = run(f"{git} rev-parse HEAD").strip()
|
198 |
+
except Exception:
|
199 |
+
commit = "<none>"
|
200 |
+
|
201 |
+
print(f"Python {sys.version}")
|
202 |
+
print(f"Commit hash: {commit}")
|
203 |
+
|
204 |
+
if not is_installed("torch") or not is_installed("torchvision"):
|
205 |
+
run(f'"{python}" -m {torch_command}', "Installing torch and torchvision", "Couldn't install torch")
|
206 |
+
|
207 |
+
if not skip_torch_cuda_test:
|
208 |
+
run_python("import torch; assert torch.cuda.is_available(), 'Torch is not able to use GPU; add --skip-torch-cuda-test to COMMANDLINE_ARGS variable to disable this check'")
|
209 |
+
|
210 |
+
if not is_installed("gfpgan"):
|
211 |
+
run_pip(f"install {gfpgan_package}", "gfpgan")
|
212 |
+
|
213 |
+
if not is_installed("clip"):
|
214 |
+
run_pip(f"install {clip_package}", "clip")
|
215 |
+
|
216 |
+
if not is_installed("open_clip"):
|
217 |
+
run_pip(f"install {openclip_package}", "open_clip")
|
218 |
+
|
219 |
+
if (not is_installed("xformers") or reinstall_xformers) and xformers:
|
220 |
+
if platform.system() == "Windows":
|
221 |
+
if platform.python_version().startswith("3.10"):
|
222 |
+
run_pip(f"install -U -I --no-deps {xformers_windows_package}", "xformers")
|
223 |
+
else:
|
224 |
+
print("Installation of xformers is not supported in this version of Python.")
|
225 |
+
print("You can also check this and build manually: https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Xformers#building-xformers-on-windows-by-duckness")
|
226 |
+
if not is_installed("xformers"):
|
227 |
+
exit(0)
|
228 |
+
elif platform.system() == "Linux":
|
229 |
+
run_pip("install xformers", "xformers")
|
230 |
+
|
231 |
+
if not is_installed("pyngrok") and ngrok:
|
232 |
+
run_pip("install pyngrok", "ngrok")
|
233 |
+
|
234 |
+
os.makedirs(dir_repos, exist_ok=True)
|
235 |
+
|
236 |
+
git_clone(stable_diffusion_repo, repo_dir('stable-diffusion-stability-ai'), "Stable Diffusion", stable_diffusion_commit_hash)
|
237 |
+
git_clone(taming_transformers_repo, repo_dir('taming-transformers'), "Taming Transformers", taming_transformers_commit_hash)
|
238 |
+
git_clone(k_diffusion_repo, repo_dir('k-diffusion'), "K-diffusion", k_diffusion_commit_hash)
|
239 |
+
git_clone(codeformer_repo, repo_dir('CodeFormer'), "CodeFormer", codeformer_commit_hash)
|
240 |
+
git_clone(blip_repo, repo_dir('BLIP'), "BLIP", blip_commit_hash)
|
241 |
+
|
242 |
+
if not is_installed("lpips"):
|
243 |
+
run_pip(f"install -r {os.path.join(repo_dir('CodeFormer'), 'requirements.txt')}", "requirements for CodeFormer")
|
244 |
+
|
245 |
+
run_pip(f"install -r {requirements_file}", "requirements for Web UI")
|
246 |
+
|
247 |
+
run_extensions_installers(settings_file=args.ui_settings_file)
|
248 |
+
|
249 |
+
if update_check:
|
250 |
+
version_check(commit)
|
251 |
+
|
252 |
+
if "--exit" in sys.argv:
|
253 |
+
print("Exiting because of --exit argument")
|
254 |
+
exit(0)
|
255 |
+
|
256 |
+
if run_tests:
|
257 |
+
exitcode = tests(test_dir)
|
258 |
+
exit(exitcode)
|
259 |
+
|
260 |
+
|
261 |
+
def tests(test_dir):
|
262 |
+
if "--api" not in sys.argv:
|
263 |
+
sys.argv.append("--api")
|
264 |
+
if "--ckpt" not in sys.argv:
|
265 |
+
sys.argv.append("--ckpt")
|
266 |
+
sys.argv.append("./test/test_files/empty.pt")
|
267 |
+
if "--skip-torch-cuda-test" not in sys.argv:
|
268 |
+
sys.argv.append("--skip-torch-cuda-test")
|
269 |
+
|
270 |
+
print(f"Launching Web UI in another process for testing with arguments: {' '.join(sys.argv[1:])}")
|
271 |
+
|
272 |
+
with open('test/stdout.txt', "w", encoding="utf8") as stdout, open('test/stderr.txt', "w", encoding="utf8") as stderr:
|
273 |
+
proc = subprocess.Popen([sys.executable, *sys.argv], stdout=stdout, stderr=stderr)
|
274 |
+
|
275 |
+
import test.server_poll
|
276 |
+
exitcode = test.server_poll.run_tests(proc, test_dir)
|
277 |
+
|
278 |
+
print(f"Stopping Web UI process with id {proc.pid}")
|
279 |
+
proc.kill()
|
280 |
+
return exitcode
|
281 |
+
|
282 |
+
|
283 |
+
def start():
|
284 |
+
print(f"Launching {'API server' if '--nowebui' in sys.argv else 'Web UI'} with arguments: {' '.join(sys.argv[1:])}")
|
285 |
+
import webui
|
286 |
+
if '--nowebui' in sys.argv:
|
287 |
+
webui.api_only()
|
288 |
+
else:
|
289 |
+
webui.webui()
|
290 |
+
|
291 |
+
|
292 |
+
if __name__ == "__main__":
|
293 |
+
prepare_enviroment()
|
294 |
+
start()
|
stable-diffusion-webui-master/localizations/Put localization files here.txt
ADDED
File without changes
|
stable-diffusion-webui-master/models/Stable-diffusion/Put Stable Diffusion checkpoints here.txt
ADDED
File without changes
|
stable-diffusion-webui-master/models/VAE/Put VAE here.txt
ADDED
File without changes
|
stable-diffusion-webui-master/models/deepbooru/Put your deepbooru release project folder here.txt
ADDED
File without changes
|
stable-diffusion-webui-master/modules/api/api.py
ADDED
@@ -0,0 +1,329 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import base64
|
2 |
+
import io
|
3 |
+
import time
|
4 |
+
import uvicorn
|
5 |
+
from threading import Lock
|
6 |
+
from io import BytesIO
|
7 |
+
from gradio.processing_utils import decode_base64_to_file
|
8 |
+
from fastapi import APIRouter, Depends, FastAPI, HTTPException
|
9 |
+
from fastapi.security import HTTPBasic, HTTPBasicCredentials
|
10 |
+
from secrets import compare_digest
|
11 |
+
|
12 |
+
import modules.shared as shared
|
13 |
+
from modules import sd_samplers, deepbooru
|
14 |
+
from modules.api.models import *
|
15 |
+
from modules.processing import StableDiffusionProcessingTxt2Img, StableDiffusionProcessingImg2Img, process_images
|
16 |
+
from modules.extras import run_extras, run_pnginfo
|
17 |
+
from PIL import PngImagePlugin,Image
|
18 |
+
from modules.sd_models import checkpoints_list
|
19 |
+
from modules.realesrgan_model import get_realesrgan_models
|
20 |
+
from typing import List
|
21 |
+
|
22 |
+
def upscaler_to_index(name: str):
|
23 |
+
try:
|
24 |
+
return [x.name.lower() for x in shared.sd_upscalers].index(name.lower())
|
25 |
+
except:
|
26 |
+
raise HTTPException(status_code=400, detail=f"Invalid upscaler, needs to be on of these: {' , '.join([x.name for x in sd_upscalers])}")
|
27 |
+
|
28 |
+
|
29 |
+
def validate_sampler_name(name):
|
30 |
+
config = sd_samplers.all_samplers_map.get(name, None)
|
31 |
+
if config is None:
|
32 |
+
raise HTTPException(status_code=404, detail="Sampler not found")
|
33 |
+
|
34 |
+
return name
|
35 |
+
|
36 |
+
def setUpscalers(req: dict):
|
37 |
+
reqDict = vars(req)
|
38 |
+
reqDict['extras_upscaler_1'] = upscaler_to_index(req.upscaler_1)
|
39 |
+
reqDict['extras_upscaler_2'] = upscaler_to_index(req.upscaler_2)
|
40 |
+
reqDict.pop('upscaler_1')
|
41 |
+
reqDict.pop('upscaler_2')
|
42 |
+
return reqDict
|
43 |
+
|
44 |
+
def decode_base64_to_image(encoding):
|
45 |
+
if encoding.startswith("data:image/"):
|
46 |
+
encoding = encoding.split(";")[1].split(",")[1]
|
47 |
+
return Image.open(BytesIO(base64.b64decode(encoding)))
|
48 |
+
|
49 |
+
def encode_pil_to_base64(image):
|
50 |
+
with io.BytesIO() as output_bytes:
|
51 |
+
|
52 |
+
# Copy any text-only metadata
|
53 |
+
use_metadata = False
|
54 |
+
metadata = PngImagePlugin.PngInfo()
|
55 |
+
for key, value in image.info.items():
|
56 |
+
if isinstance(key, str) and isinstance(value, str):
|
57 |
+
metadata.add_text(key, value)
|
58 |
+
use_metadata = True
|
59 |
+
|
60 |
+
image.save(
|
61 |
+
output_bytes, "PNG", pnginfo=(metadata if use_metadata else None)
|
62 |
+
)
|
63 |
+
bytes_data = output_bytes.getvalue()
|
64 |
+
return base64.b64encode(bytes_data)
|
65 |
+
|
66 |
+
|
67 |
+
class Api:
|
68 |
+
def __init__(self, app: FastAPI, queue_lock: Lock):
|
69 |
+
if shared.cmd_opts.api_auth:
|
70 |
+
self.credenticals = dict()
|
71 |
+
for auth in shared.cmd_opts.api_auth.split(","):
|
72 |
+
user, password = auth.split(":")
|
73 |
+
self.credenticals[user] = password
|
74 |
+
|
75 |
+
self.router = APIRouter()
|
76 |
+
self.app = app
|
77 |
+
self.queue_lock = queue_lock
|
78 |
+
self.add_api_route("/sdapi/v1/txt2img", self.text2imgapi, methods=["POST"], response_model=TextToImageResponse)
|
79 |
+
self.add_api_route("/sdapi/v1/img2img", self.img2imgapi, methods=["POST"], response_model=ImageToImageResponse)
|
80 |
+
self.add_api_route("/sdapi/v1/extra-single-image", self.extras_single_image_api, methods=["POST"], response_model=ExtrasSingleImageResponse)
|
81 |
+
self.add_api_route("/sdapi/v1/extra-batch-images", self.extras_batch_images_api, methods=["POST"], response_model=ExtrasBatchImagesResponse)
|
82 |
+
self.add_api_route("/sdapi/v1/png-info", self.pnginfoapi, methods=["POST"], response_model=PNGInfoResponse)
|
83 |
+
self.add_api_route("/sdapi/v1/progress", self.progressapi, methods=["GET"], response_model=ProgressResponse)
|
84 |
+
self.add_api_route("/sdapi/v1/interrogate", self.interrogateapi, methods=["POST"])
|
85 |
+
self.add_api_route("/sdapi/v1/interrupt", self.interruptapi, methods=["POST"])
|
86 |
+
self.add_api_route("/sdapi/v1/skip", self.skip, methods=["POST"])
|
87 |
+
self.add_api_route("/sdapi/v1/options", self.get_config, methods=["GET"], response_model=OptionsModel)
|
88 |
+
self.add_api_route("/sdapi/v1/options", self.set_config, methods=["POST"])
|
89 |
+
self.add_api_route("/sdapi/v1/cmd-flags", self.get_cmd_flags, methods=["GET"], response_model=FlagsModel)
|
90 |
+
self.add_api_route("/sdapi/v1/samplers", self.get_samplers, methods=["GET"], response_model=List[SamplerItem])
|
91 |
+
self.add_api_route("/sdapi/v1/upscalers", self.get_upscalers, methods=["GET"], response_model=List[UpscalerItem])
|
92 |
+
self.add_api_route("/sdapi/v1/sd-models", self.get_sd_models, methods=["GET"], response_model=List[SDModelItem])
|
93 |
+
self.add_api_route("/sdapi/v1/hypernetworks", self.get_hypernetworks, methods=["GET"], response_model=List[HypernetworkItem])
|
94 |
+
self.add_api_route("/sdapi/v1/face-restorers", self.get_face_restorers, methods=["GET"], response_model=List[FaceRestorerItem])
|
95 |
+
self.add_api_route("/sdapi/v1/realesrgan-models", self.get_realesrgan_models, methods=["GET"], response_model=List[RealesrganItem])
|
96 |
+
self.add_api_route("/sdapi/v1/prompt-styles", self.get_promp_styles, methods=["GET"], response_model=List[PromptStyleItem])
|
97 |
+
self.add_api_route("/sdapi/v1/artist-categories", self.get_artists_categories, methods=["GET"], response_model=List[str])
|
98 |
+
self.add_api_route("/sdapi/v1/artists", self.get_artists, methods=["GET"], response_model=List[ArtistItem])
|
99 |
+
|
100 |
+
def add_api_route(self, path: str, endpoint, **kwargs):
|
101 |
+
if shared.cmd_opts.api_auth:
|
102 |
+
return self.app.add_api_route(path, endpoint, dependencies=[Depends(self.auth)], **kwargs)
|
103 |
+
return self.app.add_api_route(path, endpoint, **kwargs)
|
104 |
+
|
105 |
+
def auth(self, credenticals: HTTPBasicCredentials = Depends(HTTPBasic())):
|
106 |
+
if credenticals.username in self.credenticals:
|
107 |
+
if compare_digest(credenticals.password, self.credenticals[credenticals.username]):
|
108 |
+
return True
|
109 |
+
|
110 |
+
raise HTTPException(status_code=401, detail="Incorrect username or password", headers={"WWW-Authenticate": "Basic"})
|
111 |
+
|
112 |
+
def text2imgapi(self, txt2imgreq: StableDiffusionTxt2ImgProcessingAPI):
|
113 |
+
populate = txt2imgreq.copy(update={ # Override __init__ params
|
114 |
+
"sd_model": shared.sd_model,
|
115 |
+
"sampler_name": validate_sampler_name(txt2imgreq.sampler_name or txt2imgreq.sampler_index),
|
116 |
+
"do_not_save_samples": True,
|
117 |
+
"do_not_save_grid": True
|
118 |
+
}
|
119 |
+
)
|
120 |
+
if populate.sampler_name:
|
121 |
+
populate.sampler_index = None # prevent a warning later on
|
122 |
+
p = StableDiffusionProcessingTxt2Img(**vars(populate))
|
123 |
+
# Override object param
|
124 |
+
|
125 |
+
shared.state.begin()
|
126 |
+
|
127 |
+
with self.queue_lock:
|
128 |
+
processed = process_images(p)
|
129 |
+
|
130 |
+
shared.state.end()
|
131 |
+
|
132 |
+
b64images = list(map(encode_pil_to_base64, processed.images))
|
133 |
+
|
134 |
+
return TextToImageResponse(images=b64images, parameters=vars(txt2imgreq), info=processed.js())
|
135 |
+
|
136 |
+
def img2imgapi(self, img2imgreq: StableDiffusionImg2ImgProcessingAPI):
|
137 |
+
init_images = img2imgreq.init_images
|
138 |
+
if init_images is None:
|
139 |
+
raise HTTPException(status_code=404, detail="Init image not found")
|
140 |
+
|
141 |
+
mask = img2imgreq.mask
|
142 |
+
if mask:
|
143 |
+
mask = decode_base64_to_image(mask)
|
144 |
+
|
145 |
+
populate = img2imgreq.copy(update={ # Override __init__ params
|
146 |
+
"sd_model": shared.sd_model,
|
147 |
+
"sampler_name": validate_sampler_name(img2imgreq.sampler_name or img2imgreq.sampler_index),
|
148 |
+
"do_not_save_samples": True,
|
149 |
+
"do_not_save_grid": True,
|
150 |
+
"mask": mask
|
151 |
+
}
|
152 |
+
)
|
153 |
+
if populate.sampler_name:
|
154 |
+
populate.sampler_index = None # prevent a warning later on
|
155 |
+
p = StableDiffusionProcessingImg2Img(**vars(populate))
|
156 |
+
|
157 |
+
imgs = []
|
158 |
+
for img in init_images:
|
159 |
+
img = decode_base64_to_image(img)
|
160 |
+
imgs = [img] * p.batch_size
|
161 |
+
|
162 |
+
p.init_images = imgs
|
163 |
+
|
164 |
+
shared.state.begin()
|
165 |
+
|
166 |
+
with self.queue_lock:
|
167 |
+
processed = process_images(p)
|
168 |
+
|
169 |
+
shared.state.end()
|
170 |
+
|
171 |
+
b64images = list(map(encode_pil_to_base64, processed.images))
|
172 |
+
|
173 |
+
if (not img2imgreq.include_init_images):
|
174 |
+
img2imgreq.init_images = None
|
175 |
+
img2imgreq.mask = None
|
176 |
+
|
177 |
+
return ImageToImageResponse(images=b64images, parameters=vars(img2imgreq), info=processed.js())
|
178 |
+
|
179 |
+
def extras_single_image_api(self, req: ExtrasSingleImageRequest):
|
180 |
+
reqDict = setUpscalers(req)
|
181 |
+
|
182 |
+
reqDict['image'] = decode_base64_to_image(reqDict['image'])
|
183 |
+
|
184 |
+
with self.queue_lock:
|
185 |
+
result = run_extras(extras_mode=0, image_folder="", input_dir="", output_dir="", **reqDict)
|
186 |
+
|
187 |
+
return ExtrasSingleImageResponse(image=encode_pil_to_base64(result[0][0]), html_info=result[1])
|
188 |
+
|
189 |
+
def extras_batch_images_api(self, req: ExtrasBatchImagesRequest):
|
190 |
+
reqDict = setUpscalers(req)
|
191 |
+
|
192 |
+
def prepareFiles(file):
|
193 |
+
file = decode_base64_to_file(file.data, file_path=file.name)
|
194 |
+
file.orig_name = file.name
|
195 |
+
return file
|
196 |
+
|
197 |
+
reqDict['image_folder'] = list(map(prepareFiles, reqDict['imageList']))
|
198 |
+
reqDict.pop('imageList')
|
199 |
+
|
200 |
+
with self.queue_lock:
|
201 |
+
result = run_extras(extras_mode=1, image="", input_dir="", output_dir="", **reqDict)
|
202 |
+
|
203 |
+
return ExtrasBatchImagesResponse(images=list(map(encode_pil_to_base64, result[0])), html_info=result[1])
|
204 |
+
|
205 |
+
def pnginfoapi(self, req: PNGInfoRequest):
|
206 |
+
if(not req.image.strip()):
|
207 |
+
return PNGInfoResponse(info="")
|
208 |
+
|
209 |
+
result = run_pnginfo(decode_base64_to_image(req.image.strip()))
|
210 |
+
|
211 |
+
return PNGInfoResponse(info=result[1])
|
212 |
+
|
213 |
+
def progressapi(self, req: ProgressRequest = Depends()):
|
214 |
+
# copy from check_progress_call of ui.py
|
215 |
+
|
216 |
+
if shared.state.job_count == 0:
|
217 |
+
return ProgressResponse(progress=0, eta_relative=0, state=shared.state.dict())
|
218 |
+
|
219 |
+
# avoid dividing zero
|
220 |
+
progress = 0.01
|
221 |
+
|
222 |
+
if shared.state.job_count > 0:
|
223 |
+
progress += shared.state.job_no / shared.state.job_count
|
224 |
+
if shared.state.sampling_steps > 0:
|
225 |
+
progress += 1 / shared.state.job_count * shared.state.sampling_step / shared.state.sampling_steps
|
226 |
+
|
227 |
+
time_since_start = time.time() - shared.state.time_start
|
228 |
+
eta = (time_since_start/progress)
|
229 |
+
eta_relative = eta-time_since_start
|
230 |
+
|
231 |
+
progress = min(progress, 1)
|
232 |
+
|
233 |
+
shared.state.set_current_image()
|
234 |
+
|
235 |
+
current_image = None
|
236 |
+
if shared.state.current_image and not req.skip_current_image:
|
237 |
+
current_image = encode_pil_to_base64(shared.state.current_image)
|
238 |
+
|
239 |
+
return ProgressResponse(progress=progress, eta_relative=eta_relative, state=shared.state.dict(), current_image=current_image)
|
240 |
+
|
241 |
+
def interrogateapi(self, interrogatereq: InterrogateRequest):
|
242 |
+
image_b64 = interrogatereq.image
|
243 |
+
if image_b64 is None:
|
244 |
+
raise HTTPException(status_code=404, detail="Image not found")
|
245 |
+
|
246 |
+
img = decode_base64_to_image(image_b64)
|
247 |
+
img = img.convert('RGB')
|
248 |
+
|
249 |
+
# Override object param
|
250 |
+
with self.queue_lock:
|
251 |
+
if interrogatereq.model == "clip":
|
252 |
+
processed = shared.interrogator.interrogate(img)
|
253 |
+
elif interrogatereq.model == "deepdanbooru":
|
254 |
+
processed = deepbooru.model.tag(img)
|
255 |
+
else:
|
256 |
+
raise HTTPException(status_code=404, detail="Model not found")
|
257 |
+
|
258 |
+
return InterrogateResponse(caption=processed)
|
259 |
+
|
260 |
+
def interruptapi(self):
|
261 |
+
shared.state.interrupt()
|
262 |
+
|
263 |
+
return {}
|
264 |
+
|
265 |
+
def skip(self):
|
266 |
+
shared.state.skip()
|
267 |
+
|
268 |
+
def get_config(self):
|
269 |
+
options = {}
|
270 |
+
for key in shared.opts.data.keys():
|
271 |
+
metadata = shared.opts.data_labels.get(key)
|
272 |
+
if(metadata is not None):
|
273 |
+
options.update({key: shared.opts.data.get(key, shared.opts.data_labels.get(key).default)})
|
274 |
+
else:
|
275 |
+
options.update({key: shared.opts.data.get(key, None)})
|
276 |
+
|
277 |
+
return options
|
278 |
+
|
279 |
+
def set_config(self, req: Dict[str, Any]):
|
280 |
+
for k, v in req.items():
|
281 |
+
shared.opts.set(k, v)
|
282 |
+
|
283 |
+
shared.opts.save(shared.config_filename)
|
284 |
+
return
|
285 |
+
|
286 |
+
def get_cmd_flags(self):
|
287 |
+
return vars(shared.cmd_opts)
|
288 |
+
|
289 |
+
def get_samplers(self):
|
290 |
+
return [{"name": sampler[0], "aliases":sampler[2], "options":sampler[3]} for sampler in sd_samplers.all_samplers]
|
291 |
+
|
292 |
+
def get_upscalers(self):
|
293 |
+
upscalers = []
|
294 |
+
|
295 |
+
for upscaler in shared.sd_upscalers:
|
296 |
+
u = upscaler.scaler
|
297 |
+
upscalers.append({"name":u.name, "model_name":u.model_name, "model_path":u.model_path, "model_url":u.model_url})
|
298 |
+
|
299 |
+
return upscalers
|
300 |
+
|
301 |
+
def get_sd_models(self):
|
302 |
+
return [{"title":x.title, "model_name":x.model_name, "hash":x.hash, "filename": x.filename, "config": x.config} for x in checkpoints_list.values()]
|
303 |
+
|
304 |
+
def get_hypernetworks(self):
|
305 |
+
return [{"name": name, "path": shared.hypernetworks[name]} for name in shared.hypernetworks]
|
306 |
+
|
307 |
+
def get_face_restorers(self):
|
308 |
+
return [{"name":x.name(), "cmd_dir": getattr(x, "cmd_dir", None)} for x in shared.face_restorers]
|
309 |
+
|
310 |
+
def get_realesrgan_models(self):
|
311 |
+
return [{"name":x.name,"path":x.data_path, "scale":x.scale} for x in get_realesrgan_models(None)]
|
312 |
+
|
313 |
+
def get_promp_styles(self):
|
314 |
+
styleList = []
|
315 |
+
for k in shared.prompt_styles.styles:
|
316 |
+
style = shared.prompt_styles.styles[k]
|
317 |
+
styleList.append({"name":style[0], "prompt": style[1], "negative_prompt": style[2]})
|
318 |
+
|
319 |
+
return styleList
|
320 |
+
|
321 |
+
def get_artists_categories(self):
|
322 |
+
return shared.artist_db.cats
|
323 |
+
|
324 |
+
def get_artists(self):
|
325 |
+
return [{"name":x[0], "score":x[1], "category":x[2]} for x in shared.artist_db.artists]
|
326 |
+
|
327 |
+
def launch(self, server_name, port):
|
328 |
+
self.app.include_router(self.router)
|
329 |
+
uvicorn.run(self.app, host=server_name, port=port)
|
stable-diffusion-webui-master/modules/api/models.py
ADDED
@@ -0,0 +1,242 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import inspect
|
2 |
+
from pydantic import BaseModel, Field, create_model
|
3 |
+
from typing import Any, Optional
|
4 |
+
from typing_extensions import Literal
|
5 |
+
from inflection import underscore
|
6 |
+
from modules.processing import StableDiffusionProcessingTxt2Img, StableDiffusionProcessingImg2Img
|
7 |
+
from modules.shared import sd_upscalers, opts, parser
|
8 |
+
from typing import Dict, List
|
9 |
+
|
10 |
+
API_NOT_ALLOWED = [
|
11 |
+
"self",
|
12 |
+
"kwargs",
|
13 |
+
"sd_model",
|
14 |
+
"outpath_samples",
|
15 |
+
"outpath_grids",
|
16 |
+
"sampler_index",
|
17 |
+
"do_not_save_samples",
|
18 |
+
"do_not_save_grid",
|
19 |
+
"extra_generation_params",
|
20 |
+
"overlay_images",
|
21 |
+
"do_not_reload_embeddings",
|
22 |
+
"seed_enable_extras",
|
23 |
+
"prompt_for_display",
|
24 |
+
"sampler_noise_scheduler_override",
|
25 |
+
"ddim_discretize"
|
26 |
+
]
|
27 |
+
|
28 |
+
class ModelDef(BaseModel):
|
29 |
+
"""Assistance Class for Pydantic Dynamic Model Generation"""
|
30 |
+
|
31 |
+
field: str
|
32 |
+
field_alias: str
|
33 |
+
field_type: Any
|
34 |
+
field_value: Any
|
35 |
+
field_exclude: bool = False
|
36 |
+
|
37 |
+
|
38 |
+
class PydanticModelGenerator:
|
39 |
+
"""
|
40 |
+
Takes in created classes and stubs them out in a way FastAPI/Pydantic is happy about:
|
41 |
+
source_data is a snapshot of the default values produced by the class
|
42 |
+
params are the names of the actual keys required by __init__
|
43 |
+
"""
|
44 |
+
|
45 |
+
def __init__(
|
46 |
+
self,
|
47 |
+
model_name: str = None,
|
48 |
+
class_instance = None,
|
49 |
+
additional_fields = None,
|
50 |
+
):
|
51 |
+
def field_type_generator(k, v):
|
52 |
+
# field_type = str if not overrides.get(k) else overrides[k]["type"]
|
53 |
+
# print(k, v.annotation, v.default)
|
54 |
+
field_type = v.annotation
|
55 |
+
|
56 |
+
return Optional[field_type]
|
57 |
+
|
58 |
+
def merge_class_params(class_):
|
59 |
+
all_classes = list(filter(lambda x: x is not object, inspect.getmro(class_)))
|
60 |
+
parameters = {}
|
61 |
+
for classes in all_classes:
|
62 |
+
parameters = {**parameters, **inspect.signature(classes.__init__).parameters}
|
63 |
+
return parameters
|
64 |
+
|
65 |
+
|
66 |
+
self._model_name = model_name
|
67 |
+
self._class_data = merge_class_params(class_instance)
|
68 |
+
|
69 |
+
self._model_def = [
|
70 |
+
ModelDef(
|
71 |
+
field=underscore(k),
|
72 |
+
field_alias=k,
|
73 |
+
field_type=field_type_generator(k, v),
|
74 |
+
field_value=v.default
|
75 |
+
)
|
76 |
+
for (k,v) in self._class_data.items() if k not in API_NOT_ALLOWED
|
77 |
+
]
|
78 |
+
|
79 |
+
for fields in additional_fields:
|
80 |
+
self._model_def.append(ModelDef(
|
81 |
+
field=underscore(fields["key"]),
|
82 |
+
field_alias=fields["key"],
|
83 |
+
field_type=fields["type"],
|
84 |
+
field_value=fields["default"],
|
85 |
+
field_exclude=fields["exclude"] if "exclude" in fields else False))
|
86 |
+
|
87 |
+
def generate_model(self):
|
88 |
+
"""
|
89 |
+
Creates a pydantic BaseModel
|
90 |
+
from the json and overrides provided at initialization
|
91 |
+
"""
|
92 |
+
fields = {
|
93 |
+
d.field: (d.field_type, Field(default=d.field_value, alias=d.field_alias, exclude=d.field_exclude)) for d in self._model_def
|
94 |
+
}
|
95 |
+
DynamicModel = create_model(self._model_name, **fields)
|
96 |
+
DynamicModel.__config__.allow_population_by_field_name = True
|
97 |
+
DynamicModel.__config__.allow_mutation = True
|
98 |
+
return DynamicModel
|
99 |
+
|
100 |
+
StableDiffusionTxt2ImgProcessingAPI = PydanticModelGenerator(
|
101 |
+
"StableDiffusionProcessingTxt2Img",
|
102 |
+
StableDiffusionProcessingTxt2Img,
|
103 |
+
[{"key": "sampler_index", "type": str, "default": "Euler"}]
|
104 |
+
).generate_model()
|
105 |
+
|
106 |
+
StableDiffusionImg2ImgProcessingAPI = PydanticModelGenerator(
|
107 |
+
"StableDiffusionProcessingImg2Img",
|
108 |
+
StableDiffusionProcessingImg2Img,
|
109 |
+
[{"key": "sampler_index", "type": str, "default": "Euler"}, {"key": "init_images", "type": list, "default": None}, {"key": "denoising_strength", "type": float, "default": 0.75}, {"key": "mask", "type": str, "default": None}, {"key": "include_init_images", "type": bool, "default": False, "exclude" : True}]
|
110 |
+
).generate_model()
|
111 |
+
|
112 |
+
class TextToImageResponse(BaseModel):
|
113 |
+
images: List[str] = Field(default=None, title="Image", description="The generated image in base64 format.")
|
114 |
+
parameters: dict
|
115 |
+
info: str
|
116 |
+
|
117 |
+
class ImageToImageResponse(BaseModel):
|
118 |
+
images: List[str] = Field(default=None, title="Image", description="The generated image in base64 format.")
|
119 |
+
parameters: dict
|
120 |
+
info: str
|
121 |
+
|
122 |
+
class ExtrasBaseRequest(BaseModel):
|
123 |
+
resize_mode: Literal[0, 1] = Field(default=0, title="Resize Mode", description="Sets the resize mode: 0 to upscale by upscaling_resize amount, 1 to upscale up to upscaling_resize_h x upscaling_resize_w.")
|
124 |
+
show_extras_results: bool = Field(default=True, title="Show results", description="Should the backend return the generated image?")
|
125 |
+
gfpgan_visibility: float = Field(default=0, title="GFPGAN Visibility", ge=0, le=1, allow_inf_nan=False, description="Sets the visibility of GFPGAN, values should be between 0 and 1.")
|
126 |
+
codeformer_visibility: float = Field(default=0, title="CodeFormer Visibility", ge=0, le=1, allow_inf_nan=False, description="Sets the visibility of CodeFormer, values should be between 0 and 1.")
|
127 |
+
codeformer_weight: float = Field(default=0, title="CodeFormer Weight", ge=0, le=1, allow_inf_nan=False, description="Sets the weight of CodeFormer, values should be between 0 and 1.")
|
128 |
+
upscaling_resize: float = Field(default=2, title="Upscaling Factor", ge=1, le=4, description="By how much to upscale the image, only used when resize_mode=0.")
|
129 |
+
upscaling_resize_w: int = Field(default=512, title="Target Width", ge=1, description="Target width for the upscaler to hit. Only used when resize_mode=1.")
|
130 |
+
upscaling_resize_h: int = Field(default=512, title="Target Height", ge=1, description="Target height for the upscaler to hit. Only used when resize_mode=1.")
|
131 |
+
upscaling_crop: bool = Field(default=True, title="Crop to fit", description="Should the upscaler crop the image to fit in the choosen size?")
|
132 |
+
upscaler_1: str = Field(default="None", title="Main upscaler", description=f"The name of the main upscaler to use, it has to be one of this list: {' , '.join([x.name for x in sd_upscalers])}")
|
133 |
+
upscaler_2: str = Field(default="None", title="Secondary upscaler", description=f"The name of the secondary upscaler to use, it has to be one of this list: {' , '.join([x.name for x in sd_upscalers])}")
|
134 |
+
extras_upscaler_2_visibility: float = Field(default=0, title="Secondary upscaler visibility", ge=0, le=1, allow_inf_nan=False, description="Sets the visibility of secondary upscaler, values should be between 0 and 1.")
|
135 |
+
upscale_first: bool = Field(default=False, title="Upscale first", description="Should the upscaler run before restoring faces?")
|
136 |
+
|
137 |
+
class ExtraBaseResponse(BaseModel):
|
138 |
+
html_info: str = Field(title="HTML info", description="A series of HTML tags containing the process info.")
|
139 |
+
|
140 |
+
class ExtrasSingleImageRequest(ExtrasBaseRequest):
|
141 |
+
image: str = Field(default="", title="Image", description="Image to work on, must be a Base64 string containing the image's data.")
|
142 |
+
|
143 |
+
class ExtrasSingleImageResponse(ExtraBaseResponse):
|
144 |
+
image: str = Field(default=None, title="Image", description="The generated image in base64 format.")
|
145 |
+
|
146 |
+
class FileData(BaseModel):
|
147 |
+
data: str = Field(title="File data", description="Base64 representation of the file")
|
148 |
+
name: str = Field(title="File name")
|
149 |
+
|
150 |
+
class ExtrasBatchImagesRequest(ExtrasBaseRequest):
|
151 |
+
imageList: List[FileData] = Field(title="Images", description="List of images to work on. Must be Base64 strings")
|
152 |
+
|
153 |
+
class ExtrasBatchImagesResponse(ExtraBaseResponse):
|
154 |
+
images: List[str] = Field(title="Images", description="The generated images in base64 format.")
|
155 |
+
|
156 |
+
class PNGInfoRequest(BaseModel):
|
157 |
+
image: str = Field(title="Image", description="The base64 encoded PNG image")
|
158 |
+
|
159 |
+
class PNGInfoResponse(BaseModel):
|
160 |
+
info: str = Field(title="Image info", description="A string with all the info the image had")
|
161 |
+
|
162 |
+
class ProgressRequest(BaseModel):
|
163 |
+
skip_current_image: bool = Field(default=False, title="Skip current image", description="Skip current image serialization")
|
164 |
+
|
165 |
+
class ProgressResponse(BaseModel):
|
166 |
+
progress: float = Field(title="Progress", description="The progress with a range of 0 to 1")
|
167 |
+
eta_relative: float = Field(title="ETA in secs")
|
168 |
+
state: dict = Field(title="State", description="The current state snapshot")
|
169 |
+
current_image: str = Field(default=None, title="Current image", description="The current image in base64 format. opts.show_progress_every_n_steps is required for this to work.")
|
170 |
+
|
171 |
+
class InterrogateRequest(BaseModel):
|
172 |
+
image: str = Field(default="", title="Image", description="Image to work on, must be a Base64 string containing the image's data.")
|
173 |
+
model: str = Field(default="clip", title="Model", description="The interrogate model used.")
|
174 |
+
|
175 |
+
class InterrogateResponse(BaseModel):
|
176 |
+
caption: str = Field(default=None, title="Caption", description="The generated caption for the image.")
|
177 |
+
|
178 |
+
fields = {}
|
179 |
+
for key, metadata in opts.data_labels.items():
|
180 |
+
value = opts.data.get(key)
|
181 |
+
optType = opts.typemap.get(type(metadata.default), type(value))
|
182 |
+
|
183 |
+
if (metadata is not None):
|
184 |
+
fields.update({key: (Optional[optType], Field(
|
185 |
+
default=metadata.default ,description=metadata.label))})
|
186 |
+
else:
|
187 |
+
fields.update({key: (Optional[optType], Field())})
|
188 |
+
|
189 |
+
OptionsModel = create_model("Options", **fields)
|
190 |
+
|
191 |
+
flags = {}
|
192 |
+
_options = vars(parser)['_option_string_actions']
|
193 |
+
for key in _options:
|
194 |
+
if(_options[key].dest != 'help'):
|
195 |
+
flag = _options[key]
|
196 |
+
_type = str
|
197 |
+
if _options[key].default is not None: _type = type(_options[key].default)
|
198 |
+
flags.update({flag.dest: (_type,Field(default=flag.default, description=flag.help))})
|
199 |
+
|
200 |
+
FlagsModel = create_model("Flags", **flags)
|
201 |
+
|
202 |
+
class SamplerItem(BaseModel):
|
203 |
+
name: str = Field(title="Name")
|
204 |
+
aliases: List[str] = Field(title="Aliases")
|
205 |
+
options: Dict[str, str] = Field(title="Options")
|
206 |
+
|
207 |
+
class UpscalerItem(BaseModel):
|
208 |
+
name: str = Field(title="Name")
|
209 |
+
model_name: Optional[str] = Field(title="Model Name")
|
210 |
+
model_path: Optional[str] = Field(title="Path")
|
211 |
+
model_url: Optional[str] = Field(title="URL")
|
212 |
+
|
213 |
+
class SDModelItem(BaseModel):
|
214 |
+
title: str = Field(title="Title")
|
215 |
+
model_name: str = Field(title="Model Name")
|
216 |
+
hash: str = Field(title="Hash")
|
217 |
+
filename: str = Field(title="Filename")
|
218 |
+
config: str = Field(title="Config file")
|
219 |
+
|
220 |
+
class HypernetworkItem(BaseModel):
|
221 |
+
name: str = Field(title="Name")
|
222 |
+
path: Optional[str] = Field(title="Path")
|
223 |
+
|
224 |
+
class FaceRestorerItem(BaseModel):
|
225 |
+
name: str = Field(title="Name")
|
226 |
+
cmd_dir: Optional[str] = Field(title="Path")
|
227 |
+
|
228 |
+
class RealesrganItem(BaseModel):
|
229 |
+
name: str = Field(title="Name")
|
230 |
+
path: Optional[str] = Field(title="Path")
|
231 |
+
scale: Optional[int] = Field(title="Scale")
|
232 |
+
|
233 |
+
class PromptStyleItem(BaseModel):
|
234 |
+
name: str = Field(title="Name")
|
235 |
+
prompt: Optional[str] = Field(title="Prompt")
|
236 |
+
negative_prompt: Optional[str] = Field(title="Negative Prompt")
|
237 |
+
|
238 |
+
class ArtistItem(BaseModel):
|
239 |
+
name: str = Field(title="Name")
|
240 |
+
score: float = Field(title="Score")
|
241 |
+
category: str = Field(title="Category")
|
242 |
+
|
stable-diffusion-webui-master/modules/artists.py
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os.path
|
2 |
+
import csv
|
3 |
+
from collections import namedtuple
|
4 |
+
|
5 |
+
Artist = namedtuple("Artist", ['name', 'weight', 'category'])
|
6 |
+
|
7 |
+
|
8 |
+
class ArtistsDatabase:
|
9 |
+
def __init__(self, filename):
|
10 |
+
self.cats = set()
|
11 |
+
self.artists = []
|
12 |
+
|
13 |
+
if not os.path.exists(filename):
|
14 |
+
return
|
15 |
+
|
16 |
+
with open(filename, "r", newline='', encoding="utf8") as file:
|
17 |
+
reader = csv.DictReader(file)
|
18 |
+
|
19 |
+
for row in reader:
|
20 |
+
artist = Artist(row["artist"], float(row["score"]), row["category"])
|
21 |
+
self.artists.append(artist)
|
22 |
+
self.cats.add(artist.category)
|
23 |
+
|
24 |
+
def categories(self):
|
25 |
+
return sorted(self.cats)
|
stable-diffusion-webui-master/modules/call_queue.py
ADDED
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import html
|
2 |
+
import sys
|
3 |
+
import threading
|
4 |
+
import traceback
|
5 |
+
import time
|
6 |
+
|
7 |
+
from modules import shared
|
8 |
+
|
9 |
+
queue_lock = threading.Lock()
|
10 |
+
|
11 |
+
|
12 |
+
def wrap_queued_call(func):
|
13 |
+
def f(*args, **kwargs):
|
14 |
+
with queue_lock:
|
15 |
+
res = func(*args, **kwargs)
|
16 |
+
|
17 |
+
return res
|
18 |
+
|
19 |
+
return f
|
20 |
+
|
21 |
+
|
22 |
+
def wrap_gradio_gpu_call(func, extra_outputs=None):
|
23 |
+
def f(*args, **kwargs):
|
24 |
+
|
25 |
+
shared.state.begin()
|
26 |
+
|
27 |
+
with queue_lock:
|
28 |
+
res = func(*args, **kwargs)
|
29 |
+
|
30 |
+
shared.state.end()
|
31 |
+
|
32 |
+
return res
|
33 |
+
|
34 |
+
return wrap_gradio_call(f, extra_outputs=extra_outputs, add_stats=True)
|
35 |
+
|
36 |
+
|
37 |
+
def wrap_gradio_call(func, extra_outputs=None, add_stats=False):
|
38 |
+
def f(*args, extra_outputs_array=extra_outputs, **kwargs):
|
39 |
+
run_memmon = shared.opts.memmon_poll_rate > 0 and not shared.mem_mon.disabled and add_stats
|
40 |
+
if run_memmon:
|
41 |
+
shared.mem_mon.monitor()
|
42 |
+
t = time.perf_counter()
|
43 |
+
|
44 |
+
try:
|
45 |
+
res = list(func(*args, **kwargs))
|
46 |
+
except Exception as e:
|
47 |
+
# When printing out our debug argument list, do not print out more than a MB of text
|
48 |
+
max_debug_str_len = 131072 # (1024*1024)/8
|
49 |
+
|
50 |
+
print("Error completing request", file=sys.stderr)
|
51 |
+
argStr = f"Arguments: {str(args)} {str(kwargs)}"
|
52 |
+
print(argStr[:max_debug_str_len], file=sys.stderr)
|
53 |
+
if len(argStr) > max_debug_str_len:
|
54 |
+
print(f"(Argument list truncated at {max_debug_str_len}/{len(argStr)} characters)", file=sys.stderr)
|
55 |
+
|
56 |
+
print(traceback.format_exc(), file=sys.stderr)
|
57 |
+
|
58 |
+
shared.state.job = ""
|
59 |
+
shared.state.job_count = 0
|
60 |
+
|
61 |
+
if extra_outputs_array is None:
|
62 |
+
extra_outputs_array = [None, '']
|
63 |
+
|
64 |
+
res = extra_outputs_array + [f"<div class='error'>{html.escape(type(e).__name__+': '+str(e))}</div>"]
|
65 |
+
|
66 |
+
shared.state.skipped = False
|
67 |
+
shared.state.interrupted = False
|
68 |
+
shared.state.job_count = 0
|
69 |
+
|
70 |
+
if not add_stats:
|
71 |
+
return tuple(res)
|
72 |
+
|
73 |
+
elapsed = time.perf_counter() - t
|
74 |
+
elapsed_m = int(elapsed // 60)
|
75 |
+
elapsed_s = elapsed % 60
|
76 |
+
elapsed_text = f"{elapsed_s:.2f}s"
|
77 |
+
if elapsed_m > 0:
|
78 |
+
elapsed_text = f"{elapsed_m}m "+elapsed_text
|
79 |
+
|
80 |
+
if run_memmon:
|
81 |
+
mem_stats = {k: -(v//-(1024*1024)) for k, v in shared.mem_mon.stop().items()}
|
82 |
+
active_peak = mem_stats['active_peak']
|
83 |
+
reserved_peak = mem_stats['reserved_peak']
|
84 |
+
sys_peak = mem_stats['system_peak']
|
85 |
+
sys_total = mem_stats['total']
|
86 |
+
sys_pct = round(sys_peak/max(sys_total, 1) * 100, 2)
|
87 |
+
|
88 |
+
vram_html = f"<p class='vram'>Torch active/reserved: {active_peak}/{reserved_peak} MiB, <wbr>Sys VRAM: {sys_peak}/{sys_total} MiB ({sys_pct}%)</p>"
|
89 |
+
else:
|
90 |
+
vram_html = ''
|
91 |
+
|
92 |
+
# last item is always HTML
|
93 |
+
res[-1] += f"<div class='performance'><p class='time'>Time taken: <wbr>{elapsed_text}</p>{vram_html}</div>"
|
94 |
+
|
95 |
+
return tuple(res)
|
96 |
+
|
97 |
+
return f
|
98 |
+
|
stable-diffusion-webui-master/modules/codeformer/codeformer_arch.py
ADDED
@@ -0,0 +1,278 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# this file is copied from CodeFormer repository. Please see comment in modules/codeformer_model.py
|
2 |
+
|
3 |
+
import math
|
4 |
+
import numpy as np
|
5 |
+
import torch
|
6 |
+
from torch import nn, Tensor
|
7 |
+
import torch.nn.functional as F
|
8 |
+
from typing import Optional, List
|
9 |
+
|
10 |
+
from modules.codeformer.vqgan_arch import *
|
11 |
+
from basicsr.utils import get_root_logger
|
12 |
+
from basicsr.utils.registry import ARCH_REGISTRY
|
13 |
+
|
14 |
+
def calc_mean_std(feat, eps=1e-5):
|
15 |
+
"""Calculate mean and std for adaptive_instance_normalization.
|
16 |
+
|
17 |
+
Args:
|
18 |
+
feat (Tensor): 4D tensor.
|
19 |
+
eps (float): A small value added to the variance to avoid
|
20 |
+
divide-by-zero. Default: 1e-5.
|
21 |
+
"""
|
22 |
+
size = feat.size()
|
23 |
+
assert len(size) == 4, 'The input feature should be 4D tensor.'
|
24 |
+
b, c = size[:2]
|
25 |
+
feat_var = feat.view(b, c, -1).var(dim=2) + eps
|
26 |
+
feat_std = feat_var.sqrt().view(b, c, 1, 1)
|
27 |
+
feat_mean = feat.view(b, c, -1).mean(dim=2).view(b, c, 1, 1)
|
28 |
+
return feat_mean, feat_std
|
29 |
+
|
30 |
+
|
31 |
+
def adaptive_instance_normalization(content_feat, style_feat):
|
32 |
+
"""Adaptive instance normalization.
|
33 |
+
|
34 |
+
Adjust the reference features to have the similar color and illuminations
|
35 |
+
as those in the degradate features.
|
36 |
+
|
37 |
+
Args:
|
38 |
+
content_feat (Tensor): The reference feature.
|
39 |
+
style_feat (Tensor): The degradate features.
|
40 |
+
"""
|
41 |
+
size = content_feat.size()
|
42 |
+
style_mean, style_std = calc_mean_std(style_feat)
|
43 |
+
content_mean, content_std = calc_mean_std(content_feat)
|
44 |
+
normalized_feat = (content_feat - content_mean.expand(size)) / content_std.expand(size)
|
45 |
+
return normalized_feat * style_std.expand(size) + style_mean.expand(size)
|
46 |
+
|
47 |
+
|
48 |
+
class PositionEmbeddingSine(nn.Module):
|
49 |
+
"""
|
50 |
+
This is a more standard version of the position embedding, very similar to the one
|
51 |
+
used by the Attention is all you need paper, generalized to work on images.
|
52 |
+
"""
|
53 |
+
|
54 |
+
def __init__(self, num_pos_feats=64, temperature=10000, normalize=False, scale=None):
|
55 |
+
super().__init__()
|
56 |
+
self.num_pos_feats = num_pos_feats
|
57 |
+
self.temperature = temperature
|
58 |
+
self.normalize = normalize
|
59 |
+
if scale is not None and normalize is False:
|
60 |
+
raise ValueError("normalize should be True if scale is passed")
|
61 |
+
if scale is None:
|
62 |
+
scale = 2 * math.pi
|
63 |
+
self.scale = scale
|
64 |
+
|
65 |
+
def forward(self, x, mask=None):
|
66 |
+
if mask is None:
|
67 |
+
mask = torch.zeros((x.size(0), x.size(2), x.size(3)), device=x.device, dtype=torch.bool)
|
68 |
+
not_mask = ~mask
|
69 |
+
y_embed = not_mask.cumsum(1, dtype=torch.float32)
|
70 |
+
x_embed = not_mask.cumsum(2, dtype=torch.float32)
|
71 |
+
if self.normalize:
|
72 |
+
eps = 1e-6
|
73 |
+
y_embed = y_embed / (y_embed[:, -1:, :] + eps) * self.scale
|
74 |
+
x_embed = x_embed / (x_embed[:, :, -1:] + eps) * self.scale
|
75 |
+
|
76 |
+
dim_t = torch.arange(self.num_pos_feats, dtype=torch.float32, device=x.device)
|
77 |
+
dim_t = self.temperature ** (2 * (dim_t // 2) / self.num_pos_feats)
|
78 |
+
|
79 |
+
pos_x = x_embed[:, :, :, None] / dim_t
|
80 |
+
pos_y = y_embed[:, :, :, None] / dim_t
|
81 |
+
pos_x = torch.stack(
|
82 |
+
(pos_x[:, :, :, 0::2].sin(), pos_x[:, :, :, 1::2].cos()), dim=4
|
83 |
+
).flatten(3)
|
84 |
+
pos_y = torch.stack(
|
85 |
+
(pos_y[:, :, :, 0::2].sin(), pos_y[:, :, :, 1::2].cos()), dim=4
|
86 |
+
).flatten(3)
|
87 |
+
pos = torch.cat((pos_y, pos_x), dim=3).permute(0, 3, 1, 2)
|
88 |
+
return pos
|
89 |
+
|
90 |
+
def _get_activation_fn(activation):
|
91 |
+
"""Return an activation function given a string"""
|
92 |
+
if activation == "relu":
|
93 |
+
return F.relu
|
94 |
+
if activation == "gelu":
|
95 |
+
return F.gelu
|
96 |
+
if activation == "glu":
|
97 |
+
return F.glu
|
98 |
+
raise RuntimeError(F"activation should be relu/gelu, not {activation}.")
|
99 |
+
|
100 |
+
|
101 |
+
class TransformerSALayer(nn.Module):
|
102 |
+
def __init__(self, embed_dim, nhead=8, dim_mlp=2048, dropout=0.0, activation="gelu"):
|
103 |
+
super().__init__()
|
104 |
+
self.self_attn = nn.MultiheadAttention(embed_dim, nhead, dropout=dropout)
|
105 |
+
# Implementation of Feedforward model - MLP
|
106 |
+
self.linear1 = nn.Linear(embed_dim, dim_mlp)
|
107 |
+
self.dropout = nn.Dropout(dropout)
|
108 |
+
self.linear2 = nn.Linear(dim_mlp, embed_dim)
|
109 |
+
|
110 |
+
self.norm1 = nn.LayerNorm(embed_dim)
|
111 |
+
self.norm2 = nn.LayerNorm(embed_dim)
|
112 |
+
self.dropout1 = nn.Dropout(dropout)
|
113 |
+
self.dropout2 = nn.Dropout(dropout)
|
114 |
+
|
115 |
+
self.activation = _get_activation_fn(activation)
|
116 |
+
|
117 |
+
def with_pos_embed(self, tensor, pos: Optional[Tensor]):
|
118 |
+
return tensor if pos is None else tensor + pos
|
119 |
+
|
120 |
+
def forward(self, tgt,
|
121 |
+
tgt_mask: Optional[Tensor] = None,
|
122 |
+
tgt_key_padding_mask: Optional[Tensor] = None,
|
123 |
+
query_pos: Optional[Tensor] = None):
|
124 |
+
|
125 |
+
# self attention
|
126 |
+
tgt2 = self.norm1(tgt)
|
127 |
+
q = k = self.with_pos_embed(tgt2, query_pos)
|
128 |
+
tgt2 = self.self_attn(q, k, value=tgt2, attn_mask=tgt_mask,
|
129 |
+
key_padding_mask=tgt_key_padding_mask)[0]
|
130 |
+
tgt = tgt + self.dropout1(tgt2)
|
131 |
+
|
132 |
+
# ffn
|
133 |
+
tgt2 = self.norm2(tgt)
|
134 |
+
tgt2 = self.linear2(self.dropout(self.activation(self.linear1(tgt2))))
|
135 |
+
tgt = tgt + self.dropout2(tgt2)
|
136 |
+
return tgt
|
137 |
+
|
138 |
+
class Fuse_sft_block(nn.Module):
|
139 |
+
def __init__(self, in_ch, out_ch):
|
140 |
+
super().__init__()
|
141 |
+
self.encode_enc = ResBlock(2*in_ch, out_ch)
|
142 |
+
|
143 |
+
self.scale = nn.Sequential(
|
144 |
+
nn.Conv2d(in_ch, out_ch, kernel_size=3, padding=1),
|
145 |
+
nn.LeakyReLU(0.2, True),
|
146 |
+
nn.Conv2d(out_ch, out_ch, kernel_size=3, padding=1))
|
147 |
+
|
148 |
+
self.shift = nn.Sequential(
|
149 |
+
nn.Conv2d(in_ch, out_ch, kernel_size=3, padding=1),
|
150 |
+
nn.LeakyReLU(0.2, True),
|
151 |
+
nn.Conv2d(out_ch, out_ch, kernel_size=3, padding=1))
|
152 |
+
|
153 |
+
def forward(self, enc_feat, dec_feat, w=1):
|
154 |
+
enc_feat = self.encode_enc(torch.cat([enc_feat, dec_feat], dim=1))
|
155 |
+
scale = self.scale(enc_feat)
|
156 |
+
shift = self.shift(enc_feat)
|
157 |
+
residual = w * (dec_feat * scale + shift)
|
158 |
+
out = dec_feat + residual
|
159 |
+
return out
|
160 |
+
|
161 |
+
|
162 |
+
@ARCH_REGISTRY.register()
|
163 |
+
class CodeFormer(VQAutoEncoder):
|
164 |
+
def __init__(self, dim_embd=512, n_head=8, n_layers=9,
|
165 |
+
codebook_size=1024, latent_size=256,
|
166 |
+
connect_list=['32', '64', '128', '256'],
|
167 |
+
fix_modules=['quantize','generator']):
|
168 |
+
super(CodeFormer, self).__init__(512, 64, [1, 2, 2, 4, 4, 8], 'nearest',2, [16], codebook_size)
|
169 |
+
|
170 |
+
if fix_modules is not None:
|
171 |
+
for module in fix_modules:
|
172 |
+
for param in getattr(self, module).parameters():
|
173 |
+
param.requires_grad = False
|
174 |
+
|
175 |
+
self.connect_list = connect_list
|
176 |
+
self.n_layers = n_layers
|
177 |
+
self.dim_embd = dim_embd
|
178 |
+
self.dim_mlp = dim_embd*2
|
179 |
+
|
180 |
+
self.position_emb = nn.Parameter(torch.zeros(latent_size, self.dim_embd))
|
181 |
+
self.feat_emb = nn.Linear(256, self.dim_embd)
|
182 |
+
|
183 |
+
# transformer
|
184 |
+
self.ft_layers = nn.Sequential(*[TransformerSALayer(embed_dim=dim_embd, nhead=n_head, dim_mlp=self.dim_mlp, dropout=0.0)
|
185 |
+
for _ in range(self.n_layers)])
|
186 |
+
|
187 |
+
# logits_predict head
|
188 |
+
self.idx_pred_layer = nn.Sequential(
|
189 |
+
nn.LayerNorm(dim_embd),
|
190 |
+
nn.Linear(dim_embd, codebook_size, bias=False))
|
191 |
+
|
192 |
+
self.channels = {
|
193 |
+
'16': 512,
|
194 |
+
'32': 256,
|
195 |
+
'64': 256,
|
196 |
+
'128': 128,
|
197 |
+
'256': 128,
|
198 |
+
'512': 64,
|
199 |
+
}
|
200 |
+
|
201 |
+
# after second residual block for > 16, before attn layer for ==16
|
202 |
+
self.fuse_encoder_block = {'512':2, '256':5, '128':8, '64':11, '32':14, '16':18}
|
203 |
+
# after first residual block for > 16, before attn layer for ==16
|
204 |
+
self.fuse_generator_block = {'16':6, '32': 9, '64':12, '128':15, '256':18, '512':21}
|
205 |
+
|
206 |
+
# fuse_convs_dict
|
207 |
+
self.fuse_convs_dict = nn.ModuleDict()
|
208 |
+
for f_size in self.connect_list:
|
209 |
+
in_ch = self.channels[f_size]
|
210 |
+
self.fuse_convs_dict[f_size] = Fuse_sft_block(in_ch, in_ch)
|
211 |
+
|
212 |
+
def _init_weights(self, module):
|
213 |
+
if isinstance(module, (nn.Linear, nn.Embedding)):
|
214 |
+
module.weight.data.normal_(mean=0.0, std=0.02)
|
215 |
+
if isinstance(module, nn.Linear) and module.bias is not None:
|
216 |
+
module.bias.data.zero_()
|
217 |
+
elif isinstance(module, nn.LayerNorm):
|
218 |
+
module.bias.data.zero_()
|
219 |
+
module.weight.data.fill_(1.0)
|
220 |
+
|
221 |
+
def forward(self, x, w=0, detach_16=True, code_only=False, adain=False):
|
222 |
+
# ################### Encoder #####################
|
223 |
+
enc_feat_dict = {}
|
224 |
+
out_list = [self.fuse_encoder_block[f_size] for f_size in self.connect_list]
|
225 |
+
for i, block in enumerate(self.encoder.blocks):
|
226 |
+
x = block(x)
|
227 |
+
if i in out_list:
|
228 |
+
enc_feat_dict[str(x.shape[-1])] = x.clone()
|
229 |
+
|
230 |
+
lq_feat = x
|
231 |
+
# ################# Transformer ###################
|
232 |
+
# quant_feat, codebook_loss, quant_stats = self.quantize(lq_feat)
|
233 |
+
pos_emb = self.position_emb.unsqueeze(1).repeat(1,x.shape[0],1)
|
234 |
+
# BCHW -> BC(HW) -> (HW)BC
|
235 |
+
feat_emb = self.feat_emb(lq_feat.flatten(2).permute(2,0,1))
|
236 |
+
query_emb = feat_emb
|
237 |
+
# Transformer encoder
|
238 |
+
for layer in self.ft_layers:
|
239 |
+
query_emb = layer(query_emb, query_pos=pos_emb)
|
240 |
+
|
241 |
+
# output logits
|
242 |
+
logits = self.idx_pred_layer(query_emb) # (hw)bn
|
243 |
+
logits = logits.permute(1,0,2) # (hw)bn -> b(hw)n
|
244 |
+
|
245 |
+
if code_only: # for training stage II
|
246 |
+
# logits doesn't need softmax before cross_entropy loss
|
247 |
+
return logits, lq_feat
|
248 |
+
|
249 |
+
# ################# Quantization ###################
|
250 |
+
# if self.training:
|
251 |
+
# quant_feat = torch.einsum('btn,nc->btc', [soft_one_hot, self.quantize.embedding.weight])
|
252 |
+
# # b(hw)c -> bc(hw) -> bchw
|
253 |
+
# quant_feat = quant_feat.permute(0,2,1).view(lq_feat.shape)
|
254 |
+
# ------------
|
255 |
+
soft_one_hot = F.softmax(logits, dim=2)
|
256 |
+
_, top_idx = torch.topk(soft_one_hot, 1, dim=2)
|
257 |
+
quant_feat = self.quantize.get_codebook_feat(top_idx, shape=[x.shape[0],16,16,256])
|
258 |
+
# preserve gradients
|
259 |
+
# quant_feat = lq_feat + (quant_feat - lq_feat).detach()
|
260 |
+
|
261 |
+
if detach_16:
|
262 |
+
quant_feat = quant_feat.detach() # for training stage III
|
263 |
+
if adain:
|
264 |
+
quant_feat = adaptive_instance_normalization(quant_feat, lq_feat)
|
265 |
+
|
266 |
+
# ################## Generator ####################
|
267 |
+
x = quant_feat
|
268 |
+
fuse_list = [self.fuse_generator_block[f_size] for f_size in self.connect_list]
|
269 |
+
|
270 |
+
for i, block in enumerate(self.generator.blocks):
|
271 |
+
x = block(x)
|
272 |
+
if i in fuse_list: # fuse after i-th block
|
273 |
+
f_size = str(x.shape[-1])
|
274 |
+
if w>0:
|
275 |
+
x = self.fuse_convs_dict[f_size](enc_feat_dict[f_size].detach(), x, w)
|
276 |
+
out = x
|
277 |
+
# logits doesn't need softmax before cross_entropy loss
|
278 |
+
return out, logits, lq_feat
|
stable-diffusion-webui-master/modules/codeformer/vqgan_arch.py
ADDED
@@ -0,0 +1,437 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# this file is copied from CodeFormer repository. Please see comment in modules/codeformer_model.py
|
2 |
+
|
3 |
+
'''
|
4 |
+
VQGAN code, adapted from the original created by the Unleashing Transformers authors:
|
5 |
+
https://github.com/samb-t/unleashing-transformers/blob/master/models/vqgan.py
|
6 |
+
|
7 |
+
'''
|
8 |
+
import numpy as np
|
9 |
+
import torch
|
10 |
+
import torch.nn as nn
|
11 |
+
import torch.nn.functional as F
|
12 |
+
import copy
|
13 |
+
from basicsr.utils import get_root_logger
|
14 |
+
from basicsr.utils.registry import ARCH_REGISTRY
|
15 |
+
|
16 |
+
def normalize(in_channels):
|
17 |
+
return torch.nn.GroupNorm(num_groups=32, num_channels=in_channels, eps=1e-6, affine=True)
|
18 |
+
|
19 |
+
|
20 |
+
@torch.jit.script
|
21 |
+
def swish(x):
|
22 |
+
return x*torch.sigmoid(x)
|
23 |
+
|
24 |
+
|
25 |
+
# Define VQVAE classes
|
26 |
+
class VectorQuantizer(nn.Module):
|
27 |
+
def __init__(self, codebook_size, emb_dim, beta):
|
28 |
+
super(VectorQuantizer, self).__init__()
|
29 |
+
self.codebook_size = codebook_size # number of embeddings
|
30 |
+
self.emb_dim = emb_dim # dimension of embedding
|
31 |
+
self.beta = beta # commitment cost used in loss term, beta * ||z_e(x)-sg[e]||^2
|
32 |
+
self.embedding = nn.Embedding(self.codebook_size, self.emb_dim)
|
33 |
+
self.embedding.weight.data.uniform_(-1.0 / self.codebook_size, 1.0 / self.codebook_size)
|
34 |
+
|
35 |
+
def forward(self, z):
|
36 |
+
# reshape z -> (batch, height, width, channel) and flatten
|
37 |
+
z = z.permute(0, 2, 3, 1).contiguous()
|
38 |
+
z_flattened = z.view(-1, self.emb_dim)
|
39 |
+
|
40 |
+
# distances from z to embeddings e_j (z - e)^2 = z^2 + e^2 - 2 e * z
|
41 |
+
d = (z_flattened ** 2).sum(dim=1, keepdim=True) + (self.embedding.weight**2).sum(1) - \
|
42 |
+
2 * torch.matmul(z_flattened, self.embedding.weight.t())
|
43 |
+
|
44 |
+
mean_distance = torch.mean(d)
|
45 |
+
# find closest encodings
|
46 |
+
# min_encoding_indices = torch.argmin(d, dim=1).unsqueeze(1)
|
47 |
+
min_encoding_scores, min_encoding_indices = torch.topk(d, 1, dim=1, largest=False)
|
48 |
+
# [0-1], higher score, higher confidence
|
49 |
+
min_encoding_scores = torch.exp(-min_encoding_scores/10)
|
50 |
+
|
51 |
+
min_encodings = torch.zeros(min_encoding_indices.shape[0], self.codebook_size).to(z)
|
52 |
+
min_encodings.scatter_(1, min_encoding_indices, 1)
|
53 |
+
|
54 |
+
# get quantized latent vectors
|
55 |
+
z_q = torch.matmul(min_encodings, self.embedding.weight).view(z.shape)
|
56 |
+
# compute loss for embedding
|
57 |
+
loss = torch.mean((z_q.detach()-z)**2) + self.beta * torch.mean((z_q - z.detach()) ** 2)
|
58 |
+
# preserve gradients
|
59 |
+
z_q = z + (z_q - z).detach()
|
60 |
+
|
61 |
+
# perplexity
|
62 |
+
e_mean = torch.mean(min_encodings, dim=0)
|
63 |
+
perplexity = torch.exp(-torch.sum(e_mean * torch.log(e_mean + 1e-10)))
|
64 |
+
# reshape back to match original input shape
|
65 |
+
z_q = z_q.permute(0, 3, 1, 2).contiguous()
|
66 |
+
|
67 |
+
return z_q, loss, {
|
68 |
+
"perplexity": perplexity,
|
69 |
+
"min_encodings": min_encodings,
|
70 |
+
"min_encoding_indices": min_encoding_indices,
|
71 |
+
"min_encoding_scores": min_encoding_scores,
|
72 |
+
"mean_distance": mean_distance
|
73 |
+
}
|
74 |
+
|
75 |
+
def get_codebook_feat(self, indices, shape):
|
76 |
+
# input indices: batch*token_num -> (batch*token_num)*1
|
77 |
+
# shape: batch, height, width, channel
|
78 |
+
indices = indices.view(-1,1)
|
79 |
+
min_encodings = torch.zeros(indices.shape[0], self.codebook_size).to(indices)
|
80 |
+
min_encodings.scatter_(1, indices, 1)
|
81 |
+
# get quantized latent vectors
|
82 |
+
z_q = torch.matmul(min_encodings.float(), self.embedding.weight)
|
83 |
+
|
84 |
+
if shape is not None: # reshape back to match original input shape
|
85 |
+
z_q = z_q.view(shape).permute(0, 3, 1, 2).contiguous()
|
86 |
+
|
87 |
+
return z_q
|
88 |
+
|
89 |
+
|
90 |
+
class GumbelQuantizer(nn.Module):
|
91 |
+
def __init__(self, codebook_size, emb_dim, num_hiddens, straight_through=False, kl_weight=5e-4, temp_init=1.0):
|
92 |
+
super().__init__()
|
93 |
+
self.codebook_size = codebook_size # number of embeddings
|
94 |
+
self.emb_dim = emb_dim # dimension of embedding
|
95 |
+
self.straight_through = straight_through
|
96 |
+
self.temperature = temp_init
|
97 |
+
self.kl_weight = kl_weight
|
98 |
+
self.proj = nn.Conv2d(num_hiddens, codebook_size, 1) # projects last encoder layer to quantized logits
|
99 |
+
self.embed = nn.Embedding(codebook_size, emb_dim)
|
100 |
+
|
101 |
+
def forward(self, z):
|
102 |
+
hard = self.straight_through if self.training else True
|
103 |
+
|
104 |
+
logits = self.proj(z)
|
105 |
+
|
106 |
+
soft_one_hot = F.gumbel_softmax(logits, tau=self.temperature, dim=1, hard=hard)
|
107 |
+
|
108 |
+
z_q = torch.einsum("b n h w, n d -> b d h w", soft_one_hot, self.embed.weight)
|
109 |
+
|
110 |
+
# + kl divergence to the prior loss
|
111 |
+
qy = F.softmax(logits, dim=1)
|
112 |
+
diff = self.kl_weight * torch.sum(qy * torch.log(qy * self.codebook_size + 1e-10), dim=1).mean()
|
113 |
+
min_encoding_indices = soft_one_hot.argmax(dim=1)
|
114 |
+
|
115 |
+
return z_q, diff, {
|
116 |
+
"min_encoding_indices": min_encoding_indices
|
117 |
+
}
|
118 |
+
|
119 |
+
|
120 |
+
class Downsample(nn.Module):
|
121 |
+
def __init__(self, in_channels):
|
122 |
+
super().__init__()
|
123 |
+
self.conv = torch.nn.Conv2d(in_channels, in_channels, kernel_size=3, stride=2, padding=0)
|
124 |
+
|
125 |
+
def forward(self, x):
|
126 |
+
pad = (0, 1, 0, 1)
|
127 |
+
x = torch.nn.functional.pad(x, pad, mode="constant", value=0)
|
128 |
+
x = self.conv(x)
|
129 |
+
return x
|
130 |
+
|
131 |
+
|
132 |
+
class Upsample(nn.Module):
|
133 |
+
def __init__(self, in_channels):
|
134 |
+
super().__init__()
|
135 |
+
self.conv = nn.Conv2d(in_channels, in_channels, kernel_size=3, stride=1, padding=1)
|
136 |
+
|
137 |
+
def forward(self, x):
|
138 |
+
x = F.interpolate(x, scale_factor=2.0, mode="nearest")
|
139 |
+
x = self.conv(x)
|
140 |
+
|
141 |
+
return x
|
142 |
+
|
143 |
+
|
144 |
+
class ResBlock(nn.Module):
|
145 |
+
def __init__(self, in_channels, out_channels=None):
|
146 |
+
super(ResBlock, self).__init__()
|
147 |
+
self.in_channels = in_channels
|
148 |
+
self.out_channels = in_channels if out_channels is None else out_channels
|
149 |
+
self.norm1 = normalize(in_channels)
|
150 |
+
self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=1, padding=1)
|
151 |
+
self.norm2 = normalize(out_channels)
|
152 |
+
self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding=1)
|
153 |
+
if self.in_channels != self.out_channels:
|
154 |
+
self.conv_out = nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=1, padding=0)
|
155 |
+
|
156 |
+
def forward(self, x_in):
|
157 |
+
x = x_in
|
158 |
+
x = self.norm1(x)
|
159 |
+
x = swish(x)
|
160 |
+
x = self.conv1(x)
|
161 |
+
x = self.norm2(x)
|
162 |
+
x = swish(x)
|
163 |
+
x = self.conv2(x)
|
164 |
+
if self.in_channels != self.out_channels:
|
165 |
+
x_in = self.conv_out(x_in)
|
166 |
+
|
167 |
+
return x + x_in
|
168 |
+
|
169 |
+
|
170 |
+
class AttnBlock(nn.Module):
|
171 |
+
def __init__(self, in_channels):
|
172 |
+
super().__init__()
|
173 |
+
self.in_channels = in_channels
|
174 |
+
|
175 |
+
self.norm = normalize(in_channels)
|
176 |
+
self.q = torch.nn.Conv2d(
|
177 |
+
in_channels,
|
178 |
+
in_channels,
|
179 |
+
kernel_size=1,
|
180 |
+
stride=1,
|
181 |
+
padding=0
|
182 |
+
)
|
183 |
+
self.k = torch.nn.Conv2d(
|
184 |
+
in_channels,
|
185 |
+
in_channels,
|
186 |
+
kernel_size=1,
|
187 |
+
stride=1,
|
188 |
+
padding=0
|
189 |
+
)
|
190 |
+
self.v = torch.nn.Conv2d(
|
191 |
+
in_channels,
|
192 |
+
in_channels,
|
193 |
+
kernel_size=1,
|
194 |
+
stride=1,
|
195 |
+
padding=0
|
196 |
+
)
|
197 |
+
self.proj_out = torch.nn.Conv2d(
|
198 |
+
in_channels,
|
199 |
+
in_channels,
|
200 |
+
kernel_size=1,
|
201 |
+
stride=1,
|
202 |
+
padding=0
|
203 |
+
)
|
204 |
+
|
205 |
+
def forward(self, x):
|
206 |
+
h_ = x
|
207 |
+
h_ = self.norm(h_)
|
208 |
+
q = self.q(h_)
|
209 |
+
k = self.k(h_)
|
210 |
+
v = self.v(h_)
|
211 |
+
|
212 |
+
# compute attention
|
213 |
+
b, c, h, w = q.shape
|
214 |
+
q = q.reshape(b, c, h*w)
|
215 |
+
q = q.permute(0, 2, 1)
|
216 |
+
k = k.reshape(b, c, h*w)
|
217 |
+
w_ = torch.bmm(q, k)
|
218 |
+
w_ = w_ * (int(c)**(-0.5))
|
219 |
+
w_ = F.softmax(w_, dim=2)
|
220 |
+
|
221 |
+
# attend to values
|
222 |
+
v = v.reshape(b, c, h*w)
|
223 |
+
w_ = w_.permute(0, 2, 1)
|
224 |
+
h_ = torch.bmm(v, w_)
|
225 |
+
h_ = h_.reshape(b, c, h, w)
|
226 |
+
|
227 |
+
h_ = self.proj_out(h_)
|
228 |
+
|
229 |
+
return x+h_
|
230 |
+
|
231 |
+
|
232 |
+
class Encoder(nn.Module):
|
233 |
+
def __init__(self, in_channels, nf, emb_dim, ch_mult, num_res_blocks, resolution, attn_resolutions):
|
234 |
+
super().__init__()
|
235 |
+
self.nf = nf
|
236 |
+
self.num_resolutions = len(ch_mult)
|
237 |
+
self.num_res_blocks = num_res_blocks
|
238 |
+
self.resolution = resolution
|
239 |
+
self.attn_resolutions = attn_resolutions
|
240 |
+
|
241 |
+
curr_res = self.resolution
|
242 |
+
in_ch_mult = (1,)+tuple(ch_mult)
|
243 |
+
|
244 |
+
blocks = []
|
245 |
+
# initial convultion
|
246 |
+
blocks.append(nn.Conv2d(in_channels, nf, kernel_size=3, stride=1, padding=1))
|
247 |
+
|
248 |
+
# residual and downsampling blocks, with attention on smaller res (16x16)
|
249 |
+
for i in range(self.num_resolutions):
|
250 |
+
block_in_ch = nf * in_ch_mult[i]
|
251 |
+
block_out_ch = nf * ch_mult[i]
|
252 |
+
for _ in range(self.num_res_blocks):
|
253 |
+
blocks.append(ResBlock(block_in_ch, block_out_ch))
|
254 |
+
block_in_ch = block_out_ch
|
255 |
+
if curr_res in attn_resolutions:
|
256 |
+
blocks.append(AttnBlock(block_in_ch))
|
257 |
+
|
258 |
+
if i != self.num_resolutions - 1:
|
259 |
+
blocks.append(Downsample(block_in_ch))
|
260 |
+
curr_res = curr_res // 2
|
261 |
+
|
262 |
+
# non-local attention block
|
263 |
+
blocks.append(ResBlock(block_in_ch, block_in_ch))
|
264 |
+
blocks.append(AttnBlock(block_in_ch))
|
265 |
+
blocks.append(ResBlock(block_in_ch, block_in_ch))
|
266 |
+
|
267 |
+
# normalise and convert to latent size
|
268 |
+
blocks.append(normalize(block_in_ch))
|
269 |
+
blocks.append(nn.Conv2d(block_in_ch, emb_dim, kernel_size=3, stride=1, padding=1))
|
270 |
+
self.blocks = nn.ModuleList(blocks)
|
271 |
+
|
272 |
+
def forward(self, x):
|
273 |
+
for block in self.blocks:
|
274 |
+
x = block(x)
|
275 |
+
|
276 |
+
return x
|
277 |
+
|
278 |
+
|
279 |
+
class Generator(nn.Module):
|
280 |
+
def __init__(self, nf, emb_dim, ch_mult, res_blocks, img_size, attn_resolutions):
|
281 |
+
super().__init__()
|
282 |
+
self.nf = nf
|
283 |
+
self.ch_mult = ch_mult
|
284 |
+
self.num_resolutions = len(self.ch_mult)
|
285 |
+
self.num_res_blocks = res_blocks
|
286 |
+
self.resolution = img_size
|
287 |
+
self.attn_resolutions = attn_resolutions
|
288 |
+
self.in_channels = emb_dim
|
289 |
+
self.out_channels = 3
|
290 |
+
block_in_ch = self.nf * self.ch_mult[-1]
|
291 |
+
curr_res = self.resolution // 2 ** (self.num_resolutions-1)
|
292 |
+
|
293 |
+
blocks = []
|
294 |
+
# initial conv
|
295 |
+
blocks.append(nn.Conv2d(self.in_channels, block_in_ch, kernel_size=3, stride=1, padding=1))
|
296 |
+
|
297 |
+
# non-local attention block
|
298 |
+
blocks.append(ResBlock(block_in_ch, block_in_ch))
|
299 |
+
blocks.append(AttnBlock(block_in_ch))
|
300 |
+
blocks.append(ResBlock(block_in_ch, block_in_ch))
|
301 |
+
|
302 |
+
for i in reversed(range(self.num_resolutions)):
|
303 |
+
block_out_ch = self.nf * self.ch_mult[i]
|
304 |
+
|
305 |
+
for _ in range(self.num_res_blocks):
|
306 |
+
blocks.append(ResBlock(block_in_ch, block_out_ch))
|
307 |
+
block_in_ch = block_out_ch
|
308 |
+
|
309 |
+
if curr_res in self.attn_resolutions:
|
310 |
+
blocks.append(AttnBlock(block_in_ch))
|
311 |
+
|
312 |
+
if i != 0:
|
313 |
+
blocks.append(Upsample(block_in_ch))
|
314 |
+
curr_res = curr_res * 2
|
315 |
+
|
316 |
+
blocks.append(normalize(block_in_ch))
|
317 |
+
blocks.append(nn.Conv2d(block_in_ch, self.out_channels, kernel_size=3, stride=1, padding=1))
|
318 |
+
|
319 |
+
self.blocks = nn.ModuleList(blocks)
|
320 |
+
|
321 |
+
|
322 |
+
def forward(self, x):
|
323 |
+
for block in self.blocks:
|
324 |
+
x = block(x)
|
325 |
+
|
326 |
+
return x
|
327 |
+
|
328 |
+
|
329 |
+
@ARCH_REGISTRY.register()
|
330 |
+
class VQAutoEncoder(nn.Module):
|
331 |
+
def __init__(self, img_size, nf, ch_mult, quantizer="nearest", res_blocks=2, attn_resolutions=[16], codebook_size=1024, emb_dim=256,
|
332 |
+
beta=0.25, gumbel_straight_through=False, gumbel_kl_weight=1e-8, model_path=None):
|
333 |
+
super().__init__()
|
334 |
+
logger = get_root_logger()
|
335 |
+
self.in_channels = 3
|
336 |
+
self.nf = nf
|
337 |
+
self.n_blocks = res_blocks
|
338 |
+
self.codebook_size = codebook_size
|
339 |
+
self.embed_dim = emb_dim
|
340 |
+
self.ch_mult = ch_mult
|
341 |
+
self.resolution = img_size
|
342 |
+
self.attn_resolutions = attn_resolutions
|
343 |
+
self.quantizer_type = quantizer
|
344 |
+
self.encoder = Encoder(
|
345 |
+
self.in_channels,
|
346 |
+
self.nf,
|
347 |
+
self.embed_dim,
|
348 |
+
self.ch_mult,
|
349 |
+
self.n_blocks,
|
350 |
+
self.resolution,
|
351 |
+
self.attn_resolutions
|
352 |
+
)
|
353 |
+
if self.quantizer_type == "nearest":
|
354 |
+
self.beta = beta #0.25
|
355 |
+
self.quantize = VectorQuantizer(self.codebook_size, self.embed_dim, self.beta)
|
356 |
+
elif self.quantizer_type == "gumbel":
|
357 |
+
self.gumbel_num_hiddens = emb_dim
|
358 |
+
self.straight_through = gumbel_straight_through
|
359 |
+
self.kl_weight = gumbel_kl_weight
|
360 |
+
self.quantize = GumbelQuantizer(
|
361 |
+
self.codebook_size,
|
362 |
+
self.embed_dim,
|
363 |
+
self.gumbel_num_hiddens,
|
364 |
+
self.straight_through,
|
365 |
+
self.kl_weight
|
366 |
+
)
|
367 |
+
self.generator = Generator(
|
368 |
+
self.nf,
|
369 |
+
self.embed_dim,
|
370 |
+
self.ch_mult,
|
371 |
+
self.n_blocks,
|
372 |
+
self.resolution,
|
373 |
+
self.attn_resolutions
|
374 |
+
)
|
375 |
+
|
376 |
+
if model_path is not None:
|
377 |
+
chkpt = torch.load(model_path, map_location='cpu')
|
378 |
+
if 'params_ema' in chkpt:
|
379 |
+
self.load_state_dict(torch.load(model_path, map_location='cpu')['params_ema'])
|
380 |
+
logger.info(f'vqgan is loaded from: {model_path} [params_ema]')
|
381 |
+
elif 'params' in chkpt:
|
382 |
+
self.load_state_dict(torch.load(model_path, map_location='cpu')['params'])
|
383 |
+
logger.info(f'vqgan is loaded from: {model_path} [params]')
|
384 |
+
else:
|
385 |
+
raise ValueError(f'Wrong params!')
|
386 |
+
|
387 |
+
|
388 |
+
def forward(self, x):
|
389 |
+
x = self.encoder(x)
|
390 |
+
quant, codebook_loss, quant_stats = self.quantize(x)
|
391 |
+
x = self.generator(quant)
|
392 |
+
return x, codebook_loss, quant_stats
|
393 |
+
|
394 |
+
|
395 |
+
|
396 |
+
# patch based discriminator
|
397 |
+
@ARCH_REGISTRY.register()
|
398 |
+
class VQGANDiscriminator(nn.Module):
|
399 |
+
def __init__(self, nc=3, ndf=64, n_layers=4, model_path=None):
|
400 |
+
super().__init__()
|
401 |
+
|
402 |
+
layers = [nn.Conv2d(nc, ndf, kernel_size=4, stride=2, padding=1), nn.LeakyReLU(0.2, True)]
|
403 |
+
ndf_mult = 1
|
404 |
+
ndf_mult_prev = 1
|
405 |
+
for n in range(1, n_layers): # gradually increase the number of filters
|
406 |
+
ndf_mult_prev = ndf_mult
|
407 |
+
ndf_mult = min(2 ** n, 8)
|
408 |
+
layers += [
|
409 |
+
nn.Conv2d(ndf * ndf_mult_prev, ndf * ndf_mult, kernel_size=4, stride=2, padding=1, bias=False),
|
410 |
+
nn.BatchNorm2d(ndf * ndf_mult),
|
411 |
+
nn.LeakyReLU(0.2, True)
|
412 |
+
]
|
413 |
+
|
414 |
+
ndf_mult_prev = ndf_mult
|
415 |
+
ndf_mult = min(2 ** n_layers, 8)
|
416 |
+
|
417 |
+
layers += [
|
418 |
+
nn.Conv2d(ndf * ndf_mult_prev, ndf * ndf_mult, kernel_size=4, stride=1, padding=1, bias=False),
|
419 |
+
nn.BatchNorm2d(ndf * ndf_mult),
|
420 |
+
nn.LeakyReLU(0.2, True)
|
421 |
+
]
|
422 |
+
|
423 |
+
layers += [
|
424 |
+
nn.Conv2d(ndf * ndf_mult, 1, kernel_size=4, stride=1, padding=1)] # output 1 channel prediction map
|
425 |
+
self.main = nn.Sequential(*layers)
|
426 |
+
|
427 |
+
if model_path is not None:
|
428 |
+
chkpt = torch.load(model_path, map_location='cpu')
|
429 |
+
if 'params_d' in chkpt:
|
430 |
+
self.load_state_dict(torch.load(model_path, map_location='cpu')['params_d'])
|
431 |
+
elif 'params' in chkpt:
|
432 |
+
self.load_state_dict(torch.load(model_path, map_location='cpu')['params'])
|
433 |
+
else:
|
434 |
+
raise ValueError(f'Wrong params!')
|
435 |
+
|
436 |
+
def forward(self, x):
|
437 |
+
return self.main(x)
|
stable-diffusion-webui-master/modules/codeformer_model.py
ADDED
@@ -0,0 +1,143 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import sys
|
3 |
+
import traceback
|
4 |
+
|
5 |
+
import cv2
|
6 |
+
import torch
|
7 |
+
|
8 |
+
import modules.face_restoration
|
9 |
+
import modules.shared
|
10 |
+
from modules import shared, devices, modelloader
|
11 |
+
from modules.paths import script_path, models_path
|
12 |
+
|
13 |
+
# codeformer people made a choice to include modified basicsr library to their project which makes
|
14 |
+
# it utterly impossible to use it alongside with other libraries that also use basicsr, like GFPGAN.
|
15 |
+
# I am making a choice to include some files from codeformer to work around this issue.
|
16 |
+
model_dir = "Codeformer"
|
17 |
+
model_path = os.path.join(models_path, model_dir)
|
18 |
+
model_url = 'https://github.com/sczhou/CodeFormer/releases/download/v0.1.0/codeformer.pth'
|
19 |
+
|
20 |
+
have_codeformer = False
|
21 |
+
codeformer = None
|
22 |
+
|
23 |
+
|
24 |
+
def setup_model(dirname):
|
25 |
+
global model_path
|
26 |
+
if not os.path.exists(model_path):
|
27 |
+
os.makedirs(model_path)
|
28 |
+
|
29 |
+
path = modules.paths.paths.get("CodeFormer", None)
|
30 |
+
if path is None:
|
31 |
+
return
|
32 |
+
|
33 |
+
try:
|
34 |
+
from torchvision.transforms.functional import normalize
|
35 |
+
from modules.codeformer.codeformer_arch import CodeFormer
|
36 |
+
from basicsr.utils.download_util import load_file_from_url
|
37 |
+
from basicsr.utils import imwrite, img2tensor, tensor2img
|
38 |
+
from facelib.utils.face_restoration_helper import FaceRestoreHelper
|
39 |
+
from facelib.detection.retinaface import retinaface
|
40 |
+
from modules.shared import cmd_opts
|
41 |
+
|
42 |
+
net_class = CodeFormer
|
43 |
+
|
44 |
+
class FaceRestorerCodeFormer(modules.face_restoration.FaceRestoration):
|
45 |
+
def name(self):
|
46 |
+
return "CodeFormer"
|
47 |
+
|
48 |
+
def __init__(self, dirname):
|
49 |
+
self.net = None
|
50 |
+
self.face_helper = None
|
51 |
+
self.cmd_dir = dirname
|
52 |
+
|
53 |
+
def create_models(self):
|
54 |
+
|
55 |
+
if self.net is not None and self.face_helper is not None:
|
56 |
+
self.net.to(devices.device_codeformer)
|
57 |
+
return self.net, self.face_helper
|
58 |
+
model_paths = modelloader.load_models(model_path, model_url, self.cmd_dir, download_name='codeformer-v0.1.0.pth')
|
59 |
+
if len(model_paths) != 0:
|
60 |
+
ckpt_path = model_paths[0]
|
61 |
+
else:
|
62 |
+
print("Unable to load codeformer model.")
|
63 |
+
return None, None
|
64 |
+
net = net_class(dim_embd=512, codebook_size=1024, n_head=8, n_layers=9, connect_list=['32', '64', '128', '256']).to(devices.device_codeformer)
|
65 |
+
checkpoint = torch.load(ckpt_path)['params_ema']
|
66 |
+
net.load_state_dict(checkpoint)
|
67 |
+
net.eval()
|
68 |
+
|
69 |
+
if hasattr(retinaface, 'device'):
|
70 |
+
retinaface.device = devices.device_codeformer
|
71 |
+
face_helper = FaceRestoreHelper(1, face_size=512, crop_ratio=(1, 1), det_model='retinaface_resnet50', save_ext='png', use_parse=True, device=devices.device_codeformer)
|
72 |
+
|
73 |
+
self.net = net
|
74 |
+
self.face_helper = face_helper
|
75 |
+
|
76 |
+
return net, face_helper
|
77 |
+
|
78 |
+
def send_model_to(self, device):
|
79 |
+
self.net.to(device)
|
80 |
+
self.face_helper.face_det.to(device)
|
81 |
+
self.face_helper.face_parse.to(device)
|
82 |
+
|
83 |
+
def restore(self, np_image, w=None):
|
84 |
+
np_image = np_image[:, :, ::-1]
|
85 |
+
|
86 |
+
original_resolution = np_image.shape[0:2]
|
87 |
+
|
88 |
+
self.create_models()
|
89 |
+
if self.net is None or self.face_helper is None:
|
90 |
+
return np_image
|
91 |
+
|
92 |
+
self.send_model_to(devices.device_codeformer)
|
93 |
+
|
94 |
+
self.face_helper.clean_all()
|
95 |
+
self.face_helper.read_image(np_image)
|
96 |
+
self.face_helper.get_face_landmarks_5(only_center_face=False, resize=640, eye_dist_threshold=5)
|
97 |
+
self.face_helper.align_warp_face()
|
98 |
+
|
99 |
+
for idx, cropped_face in enumerate(self.face_helper.cropped_faces):
|
100 |
+
cropped_face_t = img2tensor(cropped_face / 255., bgr2rgb=True, float32=True)
|
101 |
+
normalize(cropped_face_t, (0.5, 0.5, 0.5), (0.5, 0.5, 0.5), inplace=True)
|
102 |
+
cropped_face_t = cropped_face_t.unsqueeze(0).to(devices.device_codeformer)
|
103 |
+
|
104 |
+
try:
|
105 |
+
with torch.no_grad():
|
106 |
+
output = self.net(cropped_face_t, w=w if w is not None else shared.opts.code_former_weight, adain=True)[0]
|
107 |
+
restored_face = tensor2img(output, rgb2bgr=True, min_max=(-1, 1))
|
108 |
+
del output
|
109 |
+
torch.cuda.empty_cache()
|
110 |
+
except Exception as error:
|
111 |
+
print(f'\tFailed inference for CodeFormer: {error}', file=sys.stderr)
|
112 |
+
restored_face = tensor2img(cropped_face_t, rgb2bgr=True, min_max=(-1, 1))
|
113 |
+
|
114 |
+
restored_face = restored_face.astype('uint8')
|
115 |
+
self.face_helper.add_restored_face(restored_face)
|
116 |
+
|
117 |
+
self.face_helper.get_inverse_affine(None)
|
118 |
+
|
119 |
+
restored_img = self.face_helper.paste_faces_to_input_image()
|
120 |
+
restored_img = restored_img[:, :, ::-1]
|
121 |
+
|
122 |
+
if original_resolution != restored_img.shape[0:2]:
|
123 |
+
restored_img = cv2.resize(restored_img, (0, 0), fx=original_resolution[1]/restored_img.shape[1], fy=original_resolution[0]/restored_img.shape[0], interpolation=cv2.INTER_LINEAR)
|
124 |
+
|
125 |
+
self.face_helper.clean_all()
|
126 |
+
|
127 |
+
if shared.opts.face_restoration_unload:
|
128 |
+
self.send_model_to(devices.cpu)
|
129 |
+
|
130 |
+
return restored_img
|
131 |
+
|
132 |
+
global have_codeformer
|
133 |
+
have_codeformer = True
|
134 |
+
|
135 |
+
global codeformer
|
136 |
+
codeformer = FaceRestorerCodeFormer(dirname)
|
137 |
+
shared.face_restorers.append(codeformer)
|
138 |
+
|
139 |
+
except Exception:
|
140 |
+
print("Error setting up CodeFormer:", file=sys.stderr)
|
141 |
+
print(traceback.format_exc(), file=sys.stderr)
|
142 |
+
|
143 |
+
# sys.path = stored_sys_path
|
stable-diffusion-webui-master/modules/deepbooru.py
ADDED
@@ -0,0 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import re
|
3 |
+
|
4 |
+
import torch
|
5 |
+
from PIL import Image
|
6 |
+
import numpy as np
|
7 |
+
|
8 |
+
from modules import modelloader, paths, deepbooru_model, devices, images, shared
|
9 |
+
|
10 |
+
re_special = re.compile(r'([\\()])')
|
11 |
+
|
12 |
+
|
13 |
+
class DeepDanbooru:
|
14 |
+
def __init__(self):
|
15 |
+
self.model = None
|
16 |
+
|
17 |
+
def load(self):
|
18 |
+
if self.model is not None:
|
19 |
+
return
|
20 |
+
|
21 |
+
files = modelloader.load_models(
|
22 |
+
model_path=os.path.join(paths.models_path, "torch_deepdanbooru"),
|
23 |
+
model_url='https://github.com/AUTOMATIC1111/TorchDeepDanbooru/releases/download/v1/model-resnet_custom_v3.pt',
|
24 |
+
ext_filter=".pt",
|
25 |
+
download_name='model-resnet_custom_v3.pt',
|
26 |
+
)
|
27 |
+
|
28 |
+
self.model = deepbooru_model.DeepDanbooruModel()
|
29 |
+
self.model.load_state_dict(torch.load(files[0], map_location="cpu"))
|
30 |
+
|
31 |
+
self.model.eval()
|
32 |
+
self.model.to(devices.cpu, devices.dtype)
|
33 |
+
|
34 |
+
def start(self):
|
35 |
+
self.load()
|
36 |
+
self.model.to(devices.device)
|
37 |
+
|
38 |
+
def stop(self):
|
39 |
+
if not shared.opts.interrogate_keep_models_in_memory:
|
40 |
+
self.model.to(devices.cpu)
|
41 |
+
devices.torch_gc()
|
42 |
+
|
43 |
+
def tag(self, pil_image):
|
44 |
+
self.start()
|
45 |
+
res = self.tag_multi(pil_image)
|
46 |
+
self.stop()
|
47 |
+
|
48 |
+
return res
|
49 |
+
|
50 |
+
def tag_multi(self, pil_image, force_disable_ranks=False):
|
51 |
+
threshold = shared.opts.interrogate_deepbooru_score_threshold
|
52 |
+
use_spaces = shared.opts.deepbooru_use_spaces
|
53 |
+
use_escape = shared.opts.deepbooru_escape
|
54 |
+
alpha_sort = shared.opts.deepbooru_sort_alpha
|
55 |
+
include_ranks = shared.opts.interrogate_return_ranks and not force_disable_ranks
|
56 |
+
|
57 |
+
pic = images.resize_image(2, pil_image.convert("RGB"), 512, 512)
|
58 |
+
a = np.expand_dims(np.array(pic, dtype=np.float32), 0) / 255
|
59 |
+
|
60 |
+
with torch.no_grad(), devices.autocast():
|
61 |
+
x = torch.from_numpy(a).to(devices.device)
|
62 |
+
y = self.model(x)[0].detach().cpu().numpy()
|
63 |
+
|
64 |
+
probability_dict = {}
|
65 |
+
|
66 |
+
for tag, probability in zip(self.model.tags, y):
|
67 |
+
if probability < threshold:
|
68 |
+
continue
|
69 |
+
|
70 |
+
if tag.startswith("rating:"):
|
71 |
+
continue
|
72 |
+
|
73 |
+
probability_dict[tag] = probability
|
74 |
+
|
75 |
+
if alpha_sort:
|
76 |
+
tags = sorted(probability_dict)
|
77 |
+
else:
|
78 |
+
tags = [tag for tag, _ in sorted(probability_dict.items(), key=lambda x: -x[1])]
|
79 |
+
|
80 |
+
res = []
|
81 |
+
|
82 |
+
for tag in tags:
|
83 |
+
probability = probability_dict[tag]
|
84 |
+
tag_outformat = tag
|
85 |
+
if use_spaces:
|
86 |
+
tag_outformat = tag_outformat.replace('_', ' ')
|
87 |
+
if use_escape:
|
88 |
+
tag_outformat = re.sub(re_special, r'\\\1', tag_outformat)
|
89 |
+
if include_ranks:
|
90 |
+
tag_outformat = f"({tag_outformat}:{probability:.3f})"
|
91 |
+
|
92 |
+
res.append(tag_outformat)
|
93 |
+
|
94 |
+
return ", ".join(res)
|
95 |
+
|
96 |
+
|
97 |
+
model = DeepDanbooru()
|
stable-diffusion-webui-master/modules/deepbooru_model.py
ADDED
@@ -0,0 +1,676 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import torch
|
2 |
+
import torch.nn as nn
|
3 |
+
import torch.nn.functional as F
|
4 |
+
|
5 |
+
# see https://github.com/AUTOMATIC1111/TorchDeepDanbooru for more
|
6 |
+
|
7 |
+
|
8 |
+
class DeepDanbooruModel(nn.Module):
|
9 |
+
def __init__(self):
|
10 |
+
super(DeepDanbooruModel, self).__init__()
|
11 |
+
|
12 |
+
self.tags = []
|
13 |
+
|
14 |
+
self.n_Conv_0 = nn.Conv2d(kernel_size=(7, 7), in_channels=3, out_channels=64, stride=(2, 2))
|
15 |
+
self.n_MaxPool_0 = nn.MaxPool2d(kernel_size=(3, 3), stride=(2, 2))
|
16 |
+
self.n_Conv_1 = nn.Conv2d(kernel_size=(1, 1), in_channels=64, out_channels=256)
|
17 |
+
self.n_Conv_2 = nn.Conv2d(kernel_size=(1, 1), in_channels=64, out_channels=64)
|
18 |
+
self.n_Conv_3 = nn.Conv2d(kernel_size=(3, 3), in_channels=64, out_channels=64)
|
19 |
+
self.n_Conv_4 = nn.Conv2d(kernel_size=(1, 1), in_channels=64, out_channels=256)
|
20 |
+
self.n_Conv_5 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=64)
|
21 |
+
self.n_Conv_6 = nn.Conv2d(kernel_size=(3, 3), in_channels=64, out_channels=64)
|
22 |
+
self.n_Conv_7 = nn.Conv2d(kernel_size=(1, 1), in_channels=64, out_channels=256)
|
23 |
+
self.n_Conv_8 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=64)
|
24 |
+
self.n_Conv_9 = nn.Conv2d(kernel_size=(3, 3), in_channels=64, out_channels=64)
|
25 |
+
self.n_Conv_10 = nn.Conv2d(kernel_size=(1, 1), in_channels=64, out_channels=256)
|
26 |
+
self.n_Conv_11 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=512, stride=(2, 2))
|
27 |
+
self.n_Conv_12 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=128)
|
28 |
+
self.n_Conv_13 = nn.Conv2d(kernel_size=(3, 3), in_channels=128, out_channels=128, stride=(2, 2))
|
29 |
+
self.n_Conv_14 = nn.Conv2d(kernel_size=(1, 1), in_channels=128, out_channels=512)
|
30 |
+
self.n_Conv_15 = nn.Conv2d(kernel_size=(1, 1), in_channels=512, out_channels=128)
|
31 |
+
self.n_Conv_16 = nn.Conv2d(kernel_size=(3, 3), in_channels=128, out_channels=128)
|
32 |
+
self.n_Conv_17 = nn.Conv2d(kernel_size=(1, 1), in_channels=128, out_channels=512)
|
33 |
+
self.n_Conv_18 = nn.Conv2d(kernel_size=(1, 1), in_channels=512, out_channels=128)
|
34 |
+
self.n_Conv_19 = nn.Conv2d(kernel_size=(3, 3), in_channels=128, out_channels=128)
|
35 |
+
self.n_Conv_20 = nn.Conv2d(kernel_size=(1, 1), in_channels=128, out_channels=512)
|
36 |
+
self.n_Conv_21 = nn.Conv2d(kernel_size=(1, 1), in_channels=512, out_channels=128)
|
37 |
+
self.n_Conv_22 = nn.Conv2d(kernel_size=(3, 3), in_channels=128, out_channels=128)
|
38 |
+
self.n_Conv_23 = nn.Conv2d(kernel_size=(1, 1), in_channels=128, out_channels=512)
|
39 |
+
self.n_Conv_24 = nn.Conv2d(kernel_size=(1, 1), in_channels=512, out_channels=128)
|
40 |
+
self.n_Conv_25 = nn.Conv2d(kernel_size=(3, 3), in_channels=128, out_channels=128)
|
41 |
+
self.n_Conv_26 = nn.Conv2d(kernel_size=(1, 1), in_channels=128, out_channels=512)
|
42 |
+
self.n_Conv_27 = nn.Conv2d(kernel_size=(1, 1), in_channels=512, out_channels=128)
|
43 |
+
self.n_Conv_28 = nn.Conv2d(kernel_size=(3, 3), in_channels=128, out_channels=128)
|
44 |
+
self.n_Conv_29 = nn.Conv2d(kernel_size=(1, 1), in_channels=128, out_channels=512)
|
45 |
+
self.n_Conv_30 = nn.Conv2d(kernel_size=(1, 1), in_channels=512, out_channels=128)
|
46 |
+
self.n_Conv_31 = nn.Conv2d(kernel_size=(3, 3), in_channels=128, out_channels=128)
|
47 |
+
self.n_Conv_32 = nn.Conv2d(kernel_size=(1, 1), in_channels=128, out_channels=512)
|
48 |
+
self.n_Conv_33 = nn.Conv2d(kernel_size=(1, 1), in_channels=512, out_channels=128)
|
49 |
+
self.n_Conv_34 = nn.Conv2d(kernel_size=(3, 3), in_channels=128, out_channels=128)
|
50 |
+
self.n_Conv_35 = nn.Conv2d(kernel_size=(1, 1), in_channels=128, out_channels=512)
|
51 |
+
self.n_Conv_36 = nn.Conv2d(kernel_size=(1, 1), in_channels=512, out_channels=1024, stride=(2, 2))
|
52 |
+
self.n_Conv_37 = nn.Conv2d(kernel_size=(1, 1), in_channels=512, out_channels=256)
|
53 |
+
self.n_Conv_38 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256, stride=(2, 2))
|
54 |
+
self.n_Conv_39 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024)
|
55 |
+
self.n_Conv_40 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256)
|
56 |
+
self.n_Conv_41 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256)
|
57 |
+
self.n_Conv_42 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024)
|
58 |
+
self.n_Conv_43 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256)
|
59 |
+
self.n_Conv_44 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256)
|
60 |
+
self.n_Conv_45 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024)
|
61 |
+
self.n_Conv_46 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256)
|
62 |
+
self.n_Conv_47 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256)
|
63 |
+
self.n_Conv_48 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024)
|
64 |
+
self.n_Conv_49 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256)
|
65 |
+
self.n_Conv_50 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256)
|
66 |
+
self.n_Conv_51 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024)
|
67 |
+
self.n_Conv_52 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256)
|
68 |
+
self.n_Conv_53 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256)
|
69 |
+
self.n_Conv_54 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024)
|
70 |
+
self.n_Conv_55 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256)
|
71 |
+
self.n_Conv_56 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256)
|
72 |
+
self.n_Conv_57 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024)
|
73 |
+
self.n_Conv_58 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256)
|
74 |
+
self.n_Conv_59 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256)
|
75 |
+
self.n_Conv_60 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024)
|
76 |
+
self.n_Conv_61 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256)
|
77 |
+
self.n_Conv_62 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256)
|
78 |
+
self.n_Conv_63 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024)
|
79 |
+
self.n_Conv_64 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256)
|
80 |
+
self.n_Conv_65 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256)
|
81 |
+
self.n_Conv_66 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024)
|
82 |
+
self.n_Conv_67 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256)
|
83 |
+
self.n_Conv_68 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256)
|
84 |
+
self.n_Conv_69 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024)
|
85 |
+
self.n_Conv_70 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256)
|
86 |
+
self.n_Conv_71 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256)
|
87 |
+
self.n_Conv_72 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024)
|
88 |
+
self.n_Conv_73 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256)
|
89 |
+
self.n_Conv_74 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256)
|
90 |
+
self.n_Conv_75 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024)
|
91 |
+
self.n_Conv_76 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256)
|
92 |
+
self.n_Conv_77 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256)
|
93 |
+
self.n_Conv_78 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024)
|
94 |
+
self.n_Conv_79 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256)
|
95 |
+
self.n_Conv_80 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256)
|
96 |
+
self.n_Conv_81 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024)
|
97 |
+
self.n_Conv_82 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256)
|
98 |
+
self.n_Conv_83 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256)
|
99 |
+
self.n_Conv_84 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024)
|
100 |
+
self.n_Conv_85 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256)
|
101 |
+
self.n_Conv_86 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256)
|
102 |
+
self.n_Conv_87 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024)
|
103 |
+
self.n_Conv_88 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256)
|
104 |
+
self.n_Conv_89 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256)
|
105 |
+
self.n_Conv_90 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024)
|
106 |
+
self.n_Conv_91 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256)
|
107 |
+
self.n_Conv_92 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256)
|
108 |
+
self.n_Conv_93 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024)
|
109 |
+
self.n_Conv_94 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256)
|
110 |
+
self.n_Conv_95 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256)
|
111 |
+
self.n_Conv_96 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024)
|
112 |
+
self.n_Conv_97 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256)
|
113 |
+
self.n_Conv_98 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256, stride=(2, 2))
|
114 |
+
self.n_Conv_99 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024)
|
115 |
+
self.n_Conv_100 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=1024, stride=(2, 2))
|
116 |
+
self.n_Conv_101 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256)
|
117 |
+
self.n_Conv_102 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256)
|
118 |
+
self.n_Conv_103 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024)
|
119 |
+
self.n_Conv_104 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256)
|
120 |
+
self.n_Conv_105 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256)
|
121 |
+
self.n_Conv_106 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024)
|
122 |
+
self.n_Conv_107 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256)
|
123 |
+
self.n_Conv_108 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256)
|
124 |
+
self.n_Conv_109 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024)
|
125 |
+
self.n_Conv_110 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256)
|
126 |
+
self.n_Conv_111 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256)
|
127 |
+
self.n_Conv_112 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024)
|
128 |
+
self.n_Conv_113 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256)
|
129 |
+
self.n_Conv_114 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256)
|
130 |
+
self.n_Conv_115 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024)
|
131 |
+
self.n_Conv_116 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256)
|
132 |
+
self.n_Conv_117 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256)
|
133 |
+
self.n_Conv_118 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024)
|
134 |
+
self.n_Conv_119 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256)
|
135 |
+
self.n_Conv_120 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256)
|
136 |
+
self.n_Conv_121 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024)
|
137 |
+
self.n_Conv_122 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256)
|
138 |
+
self.n_Conv_123 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256)
|
139 |
+
self.n_Conv_124 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024)
|
140 |
+
self.n_Conv_125 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256)
|
141 |
+
self.n_Conv_126 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256)
|
142 |
+
self.n_Conv_127 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024)
|
143 |
+
self.n_Conv_128 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256)
|
144 |
+
self.n_Conv_129 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256)
|
145 |
+
self.n_Conv_130 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024)
|
146 |
+
self.n_Conv_131 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256)
|
147 |
+
self.n_Conv_132 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256)
|
148 |
+
self.n_Conv_133 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024)
|
149 |
+
self.n_Conv_134 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256)
|
150 |
+
self.n_Conv_135 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256)
|
151 |
+
self.n_Conv_136 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024)
|
152 |
+
self.n_Conv_137 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256)
|
153 |
+
self.n_Conv_138 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256)
|
154 |
+
self.n_Conv_139 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024)
|
155 |
+
self.n_Conv_140 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256)
|
156 |
+
self.n_Conv_141 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256)
|
157 |
+
self.n_Conv_142 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024)
|
158 |
+
self.n_Conv_143 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256)
|
159 |
+
self.n_Conv_144 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256)
|
160 |
+
self.n_Conv_145 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024)
|
161 |
+
self.n_Conv_146 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256)
|
162 |
+
self.n_Conv_147 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256)
|
163 |
+
self.n_Conv_148 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024)
|
164 |
+
self.n_Conv_149 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256)
|
165 |
+
self.n_Conv_150 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256)
|
166 |
+
self.n_Conv_151 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024)
|
167 |
+
self.n_Conv_152 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256)
|
168 |
+
self.n_Conv_153 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256)
|
169 |
+
self.n_Conv_154 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024)
|
170 |
+
self.n_Conv_155 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=256)
|
171 |
+
self.n_Conv_156 = nn.Conv2d(kernel_size=(3, 3), in_channels=256, out_channels=256)
|
172 |
+
self.n_Conv_157 = nn.Conv2d(kernel_size=(1, 1), in_channels=256, out_channels=1024)
|
173 |
+
self.n_Conv_158 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=2048, stride=(2, 2))
|
174 |
+
self.n_Conv_159 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=512)
|
175 |
+
self.n_Conv_160 = nn.Conv2d(kernel_size=(3, 3), in_channels=512, out_channels=512, stride=(2, 2))
|
176 |
+
self.n_Conv_161 = nn.Conv2d(kernel_size=(1, 1), in_channels=512, out_channels=2048)
|
177 |
+
self.n_Conv_162 = nn.Conv2d(kernel_size=(1, 1), in_channels=2048, out_channels=512)
|
178 |
+
self.n_Conv_163 = nn.Conv2d(kernel_size=(3, 3), in_channels=512, out_channels=512)
|
179 |
+
self.n_Conv_164 = nn.Conv2d(kernel_size=(1, 1), in_channels=512, out_channels=2048)
|
180 |
+
self.n_Conv_165 = nn.Conv2d(kernel_size=(1, 1), in_channels=2048, out_channels=512)
|
181 |
+
self.n_Conv_166 = nn.Conv2d(kernel_size=(3, 3), in_channels=512, out_channels=512)
|
182 |
+
self.n_Conv_167 = nn.Conv2d(kernel_size=(1, 1), in_channels=512, out_channels=2048)
|
183 |
+
self.n_Conv_168 = nn.Conv2d(kernel_size=(1, 1), in_channels=2048, out_channels=4096, stride=(2, 2))
|
184 |
+
self.n_Conv_169 = nn.Conv2d(kernel_size=(1, 1), in_channels=2048, out_channels=1024)
|
185 |
+
self.n_Conv_170 = nn.Conv2d(kernel_size=(3, 3), in_channels=1024, out_channels=1024, stride=(2, 2))
|
186 |
+
self.n_Conv_171 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=4096)
|
187 |
+
self.n_Conv_172 = nn.Conv2d(kernel_size=(1, 1), in_channels=4096, out_channels=1024)
|
188 |
+
self.n_Conv_173 = nn.Conv2d(kernel_size=(3, 3), in_channels=1024, out_channels=1024)
|
189 |
+
self.n_Conv_174 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=4096)
|
190 |
+
self.n_Conv_175 = nn.Conv2d(kernel_size=(1, 1), in_channels=4096, out_channels=1024)
|
191 |
+
self.n_Conv_176 = nn.Conv2d(kernel_size=(3, 3), in_channels=1024, out_channels=1024)
|
192 |
+
self.n_Conv_177 = nn.Conv2d(kernel_size=(1, 1), in_channels=1024, out_channels=4096)
|
193 |
+
self.n_Conv_178 = nn.Conv2d(kernel_size=(1, 1), in_channels=4096, out_channels=9176, bias=False)
|
194 |
+
|
195 |
+
def forward(self, *inputs):
|
196 |
+
t_358, = inputs
|
197 |
+
t_359 = t_358.permute(*[0, 3, 1, 2])
|
198 |
+
t_359_padded = F.pad(t_359, [2, 3, 2, 3], value=0)
|
199 |
+
t_360 = self.n_Conv_0(t_359_padded)
|
200 |
+
t_361 = F.relu(t_360)
|
201 |
+
t_361 = F.pad(t_361, [0, 1, 0, 1], value=float('-inf'))
|
202 |
+
t_362 = self.n_MaxPool_0(t_361)
|
203 |
+
t_363 = self.n_Conv_1(t_362)
|
204 |
+
t_364 = self.n_Conv_2(t_362)
|
205 |
+
t_365 = F.relu(t_364)
|
206 |
+
t_365_padded = F.pad(t_365, [1, 1, 1, 1], value=0)
|
207 |
+
t_366 = self.n_Conv_3(t_365_padded)
|
208 |
+
t_367 = F.relu(t_366)
|
209 |
+
t_368 = self.n_Conv_4(t_367)
|
210 |
+
t_369 = torch.add(t_368, t_363)
|
211 |
+
t_370 = F.relu(t_369)
|
212 |
+
t_371 = self.n_Conv_5(t_370)
|
213 |
+
t_372 = F.relu(t_371)
|
214 |
+
t_372_padded = F.pad(t_372, [1, 1, 1, 1], value=0)
|
215 |
+
t_373 = self.n_Conv_6(t_372_padded)
|
216 |
+
t_374 = F.relu(t_373)
|
217 |
+
t_375 = self.n_Conv_7(t_374)
|
218 |
+
t_376 = torch.add(t_375, t_370)
|
219 |
+
t_377 = F.relu(t_376)
|
220 |
+
t_378 = self.n_Conv_8(t_377)
|
221 |
+
t_379 = F.relu(t_378)
|
222 |
+
t_379_padded = F.pad(t_379, [1, 1, 1, 1], value=0)
|
223 |
+
t_380 = self.n_Conv_9(t_379_padded)
|
224 |
+
t_381 = F.relu(t_380)
|
225 |
+
t_382 = self.n_Conv_10(t_381)
|
226 |
+
t_383 = torch.add(t_382, t_377)
|
227 |
+
t_384 = F.relu(t_383)
|
228 |
+
t_385 = self.n_Conv_11(t_384)
|
229 |
+
t_386 = self.n_Conv_12(t_384)
|
230 |
+
t_387 = F.relu(t_386)
|
231 |
+
t_387_padded = F.pad(t_387, [0, 1, 0, 1], value=0)
|
232 |
+
t_388 = self.n_Conv_13(t_387_padded)
|
233 |
+
t_389 = F.relu(t_388)
|
234 |
+
t_390 = self.n_Conv_14(t_389)
|
235 |
+
t_391 = torch.add(t_390, t_385)
|
236 |
+
t_392 = F.relu(t_391)
|
237 |
+
t_393 = self.n_Conv_15(t_392)
|
238 |
+
t_394 = F.relu(t_393)
|
239 |
+
t_394_padded = F.pad(t_394, [1, 1, 1, 1], value=0)
|
240 |
+
t_395 = self.n_Conv_16(t_394_padded)
|
241 |
+
t_396 = F.relu(t_395)
|
242 |
+
t_397 = self.n_Conv_17(t_396)
|
243 |
+
t_398 = torch.add(t_397, t_392)
|
244 |
+
t_399 = F.relu(t_398)
|
245 |
+
t_400 = self.n_Conv_18(t_399)
|
246 |
+
t_401 = F.relu(t_400)
|
247 |
+
t_401_padded = F.pad(t_401, [1, 1, 1, 1], value=0)
|
248 |
+
t_402 = self.n_Conv_19(t_401_padded)
|
249 |
+
t_403 = F.relu(t_402)
|
250 |
+
t_404 = self.n_Conv_20(t_403)
|
251 |
+
t_405 = torch.add(t_404, t_399)
|
252 |
+
t_406 = F.relu(t_405)
|
253 |
+
t_407 = self.n_Conv_21(t_406)
|
254 |
+
t_408 = F.relu(t_407)
|
255 |
+
t_408_padded = F.pad(t_408, [1, 1, 1, 1], value=0)
|
256 |
+
t_409 = self.n_Conv_22(t_408_padded)
|
257 |
+
t_410 = F.relu(t_409)
|
258 |
+
t_411 = self.n_Conv_23(t_410)
|
259 |
+
t_412 = torch.add(t_411, t_406)
|
260 |
+
t_413 = F.relu(t_412)
|
261 |
+
t_414 = self.n_Conv_24(t_413)
|
262 |
+
t_415 = F.relu(t_414)
|
263 |
+
t_415_padded = F.pad(t_415, [1, 1, 1, 1], value=0)
|
264 |
+
t_416 = self.n_Conv_25(t_415_padded)
|
265 |
+
t_417 = F.relu(t_416)
|
266 |
+
t_418 = self.n_Conv_26(t_417)
|
267 |
+
t_419 = torch.add(t_418, t_413)
|
268 |
+
t_420 = F.relu(t_419)
|
269 |
+
t_421 = self.n_Conv_27(t_420)
|
270 |
+
t_422 = F.relu(t_421)
|
271 |
+
t_422_padded = F.pad(t_422, [1, 1, 1, 1], value=0)
|
272 |
+
t_423 = self.n_Conv_28(t_422_padded)
|
273 |
+
t_424 = F.relu(t_423)
|
274 |
+
t_425 = self.n_Conv_29(t_424)
|
275 |
+
t_426 = torch.add(t_425, t_420)
|
276 |
+
t_427 = F.relu(t_426)
|
277 |
+
t_428 = self.n_Conv_30(t_427)
|
278 |
+
t_429 = F.relu(t_428)
|
279 |
+
t_429_padded = F.pad(t_429, [1, 1, 1, 1], value=0)
|
280 |
+
t_430 = self.n_Conv_31(t_429_padded)
|
281 |
+
t_431 = F.relu(t_430)
|
282 |
+
t_432 = self.n_Conv_32(t_431)
|
283 |
+
t_433 = torch.add(t_432, t_427)
|
284 |
+
t_434 = F.relu(t_433)
|
285 |
+
t_435 = self.n_Conv_33(t_434)
|
286 |
+
t_436 = F.relu(t_435)
|
287 |
+
t_436_padded = F.pad(t_436, [1, 1, 1, 1], value=0)
|
288 |
+
t_437 = self.n_Conv_34(t_436_padded)
|
289 |
+
t_438 = F.relu(t_437)
|
290 |
+
t_439 = self.n_Conv_35(t_438)
|
291 |
+
t_440 = torch.add(t_439, t_434)
|
292 |
+
t_441 = F.relu(t_440)
|
293 |
+
t_442 = self.n_Conv_36(t_441)
|
294 |
+
t_443 = self.n_Conv_37(t_441)
|
295 |
+
t_444 = F.relu(t_443)
|
296 |
+
t_444_padded = F.pad(t_444, [0, 1, 0, 1], value=0)
|
297 |
+
t_445 = self.n_Conv_38(t_444_padded)
|
298 |
+
t_446 = F.relu(t_445)
|
299 |
+
t_447 = self.n_Conv_39(t_446)
|
300 |
+
t_448 = torch.add(t_447, t_442)
|
301 |
+
t_449 = F.relu(t_448)
|
302 |
+
t_450 = self.n_Conv_40(t_449)
|
303 |
+
t_451 = F.relu(t_450)
|
304 |
+
t_451_padded = F.pad(t_451, [1, 1, 1, 1], value=0)
|
305 |
+
t_452 = self.n_Conv_41(t_451_padded)
|
306 |
+
t_453 = F.relu(t_452)
|
307 |
+
t_454 = self.n_Conv_42(t_453)
|
308 |
+
t_455 = torch.add(t_454, t_449)
|
309 |
+
t_456 = F.relu(t_455)
|
310 |
+
t_457 = self.n_Conv_43(t_456)
|
311 |
+
t_458 = F.relu(t_457)
|
312 |
+
t_458_padded = F.pad(t_458, [1, 1, 1, 1], value=0)
|
313 |
+
t_459 = self.n_Conv_44(t_458_padded)
|
314 |
+
t_460 = F.relu(t_459)
|
315 |
+
t_461 = self.n_Conv_45(t_460)
|
316 |
+
t_462 = torch.add(t_461, t_456)
|
317 |
+
t_463 = F.relu(t_462)
|
318 |
+
t_464 = self.n_Conv_46(t_463)
|
319 |
+
t_465 = F.relu(t_464)
|
320 |
+
t_465_padded = F.pad(t_465, [1, 1, 1, 1], value=0)
|
321 |
+
t_466 = self.n_Conv_47(t_465_padded)
|
322 |
+
t_467 = F.relu(t_466)
|
323 |
+
t_468 = self.n_Conv_48(t_467)
|
324 |
+
t_469 = torch.add(t_468, t_463)
|
325 |
+
t_470 = F.relu(t_469)
|
326 |
+
t_471 = self.n_Conv_49(t_470)
|
327 |
+
t_472 = F.relu(t_471)
|
328 |
+
t_472_padded = F.pad(t_472, [1, 1, 1, 1], value=0)
|
329 |
+
t_473 = self.n_Conv_50(t_472_padded)
|
330 |
+
t_474 = F.relu(t_473)
|
331 |
+
t_475 = self.n_Conv_51(t_474)
|
332 |
+
t_476 = torch.add(t_475, t_470)
|
333 |
+
t_477 = F.relu(t_476)
|
334 |
+
t_478 = self.n_Conv_52(t_477)
|
335 |
+
t_479 = F.relu(t_478)
|
336 |
+
t_479_padded = F.pad(t_479, [1, 1, 1, 1], value=0)
|
337 |
+
t_480 = self.n_Conv_53(t_479_padded)
|
338 |
+
t_481 = F.relu(t_480)
|
339 |
+
t_482 = self.n_Conv_54(t_481)
|
340 |
+
t_483 = torch.add(t_482, t_477)
|
341 |
+
t_484 = F.relu(t_483)
|
342 |
+
t_485 = self.n_Conv_55(t_484)
|
343 |
+
t_486 = F.relu(t_485)
|
344 |
+
t_486_padded = F.pad(t_486, [1, 1, 1, 1], value=0)
|
345 |
+
t_487 = self.n_Conv_56(t_486_padded)
|
346 |
+
t_488 = F.relu(t_487)
|
347 |
+
t_489 = self.n_Conv_57(t_488)
|
348 |
+
t_490 = torch.add(t_489, t_484)
|
349 |
+
t_491 = F.relu(t_490)
|
350 |
+
t_492 = self.n_Conv_58(t_491)
|
351 |
+
t_493 = F.relu(t_492)
|
352 |
+
t_493_padded = F.pad(t_493, [1, 1, 1, 1], value=0)
|
353 |
+
t_494 = self.n_Conv_59(t_493_padded)
|
354 |
+
t_495 = F.relu(t_494)
|
355 |
+
t_496 = self.n_Conv_60(t_495)
|
356 |
+
t_497 = torch.add(t_496, t_491)
|
357 |
+
t_498 = F.relu(t_497)
|
358 |
+
t_499 = self.n_Conv_61(t_498)
|
359 |
+
t_500 = F.relu(t_499)
|
360 |
+
t_500_padded = F.pad(t_500, [1, 1, 1, 1], value=0)
|
361 |
+
t_501 = self.n_Conv_62(t_500_padded)
|
362 |
+
t_502 = F.relu(t_501)
|
363 |
+
t_503 = self.n_Conv_63(t_502)
|
364 |
+
t_504 = torch.add(t_503, t_498)
|
365 |
+
t_505 = F.relu(t_504)
|
366 |
+
t_506 = self.n_Conv_64(t_505)
|
367 |
+
t_507 = F.relu(t_506)
|
368 |
+
t_507_padded = F.pad(t_507, [1, 1, 1, 1], value=0)
|
369 |
+
t_508 = self.n_Conv_65(t_507_padded)
|
370 |
+
t_509 = F.relu(t_508)
|
371 |
+
t_510 = self.n_Conv_66(t_509)
|
372 |
+
t_511 = torch.add(t_510, t_505)
|
373 |
+
t_512 = F.relu(t_511)
|
374 |
+
t_513 = self.n_Conv_67(t_512)
|
375 |
+
t_514 = F.relu(t_513)
|
376 |
+
t_514_padded = F.pad(t_514, [1, 1, 1, 1], value=0)
|
377 |
+
t_515 = self.n_Conv_68(t_514_padded)
|
378 |
+
t_516 = F.relu(t_515)
|
379 |
+
t_517 = self.n_Conv_69(t_516)
|
380 |
+
t_518 = torch.add(t_517, t_512)
|
381 |
+
t_519 = F.relu(t_518)
|
382 |
+
t_520 = self.n_Conv_70(t_519)
|
383 |
+
t_521 = F.relu(t_520)
|
384 |
+
t_521_padded = F.pad(t_521, [1, 1, 1, 1], value=0)
|
385 |
+
t_522 = self.n_Conv_71(t_521_padded)
|
386 |
+
t_523 = F.relu(t_522)
|
387 |
+
t_524 = self.n_Conv_72(t_523)
|
388 |
+
t_525 = torch.add(t_524, t_519)
|
389 |
+
t_526 = F.relu(t_525)
|
390 |
+
t_527 = self.n_Conv_73(t_526)
|
391 |
+
t_528 = F.relu(t_527)
|
392 |
+
t_528_padded = F.pad(t_528, [1, 1, 1, 1], value=0)
|
393 |
+
t_529 = self.n_Conv_74(t_528_padded)
|
394 |
+
t_530 = F.relu(t_529)
|
395 |
+
t_531 = self.n_Conv_75(t_530)
|
396 |
+
t_532 = torch.add(t_531, t_526)
|
397 |
+
t_533 = F.relu(t_532)
|
398 |
+
t_534 = self.n_Conv_76(t_533)
|
399 |
+
t_535 = F.relu(t_534)
|
400 |
+
t_535_padded = F.pad(t_535, [1, 1, 1, 1], value=0)
|
401 |
+
t_536 = self.n_Conv_77(t_535_padded)
|
402 |
+
t_537 = F.relu(t_536)
|
403 |
+
t_538 = self.n_Conv_78(t_537)
|
404 |
+
t_539 = torch.add(t_538, t_533)
|
405 |
+
t_540 = F.relu(t_539)
|
406 |
+
t_541 = self.n_Conv_79(t_540)
|
407 |
+
t_542 = F.relu(t_541)
|
408 |
+
t_542_padded = F.pad(t_542, [1, 1, 1, 1], value=0)
|
409 |
+
t_543 = self.n_Conv_80(t_542_padded)
|
410 |
+
t_544 = F.relu(t_543)
|
411 |
+
t_545 = self.n_Conv_81(t_544)
|
412 |
+
t_546 = torch.add(t_545, t_540)
|
413 |
+
t_547 = F.relu(t_546)
|
414 |
+
t_548 = self.n_Conv_82(t_547)
|
415 |
+
t_549 = F.relu(t_548)
|
416 |
+
t_549_padded = F.pad(t_549, [1, 1, 1, 1], value=0)
|
417 |
+
t_550 = self.n_Conv_83(t_549_padded)
|
418 |
+
t_551 = F.relu(t_550)
|
419 |
+
t_552 = self.n_Conv_84(t_551)
|
420 |
+
t_553 = torch.add(t_552, t_547)
|
421 |
+
t_554 = F.relu(t_553)
|
422 |
+
t_555 = self.n_Conv_85(t_554)
|
423 |
+
t_556 = F.relu(t_555)
|
424 |
+
t_556_padded = F.pad(t_556, [1, 1, 1, 1], value=0)
|
425 |
+
t_557 = self.n_Conv_86(t_556_padded)
|
426 |
+
t_558 = F.relu(t_557)
|
427 |
+
t_559 = self.n_Conv_87(t_558)
|
428 |
+
t_560 = torch.add(t_559, t_554)
|
429 |
+
t_561 = F.relu(t_560)
|
430 |
+
t_562 = self.n_Conv_88(t_561)
|
431 |
+
t_563 = F.relu(t_562)
|
432 |
+
t_563_padded = F.pad(t_563, [1, 1, 1, 1], value=0)
|
433 |
+
t_564 = self.n_Conv_89(t_563_padded)
|
434 |
+
t_565 = F.relu(t_564)
|
435 |
+
t_566 = self.n_Conv_90(t_565)
|
436 |
+
t_567 = torch.add(t_566, t_561)
|
437 |
+
t_568 = F.relu(t_567)
|
438 |
+
t_569 = self.n_Conv_91(t_568)
|
439 |
+
t_570 = F.relu(t_569)
|
440 |
+
t_570_padded = F.pad(t_570, [1, 1, 1, 1], value=0)
|
441 |
+
t_571 = self.n_Conv_92(t_570_padded)
|
442 |
+
t_572 = F.relu(t_571)
|
443 |
+
t_573 = self.n_Conv_93(t_572)
|
444 |
+
t_574 = torch.add(t_573, t_568)
|
445 |
+
t_575 = F.relu(t_574)
|
446 |
+
t_576 = self.n_Conv_94(t_575)
|
447 |
+
t_577 = F.relu(t_576)
|
448 |
+
t_577_padded = F.pad(t_577, [1, 1, 1, 1], value=0)
|
449 |
+
t_578 = self.n_Conv_95(t_577_padded)
|
450 |
+
t_579 = F.relu(t_578)
|
451 |
+
t_580 = self.n_Conv_96(t_579)
|
452 |
+
t_581 = torch.add(t_580, t_575)
|
453 |
+
t_582 = F.relu(t_581)
|
454 |
+
t_583 = self.n_Conv_97(t_582)
|
455 |
+
t_584 = F.relu(t_583)
|
456 |
+
t_584_padded = F.pad(t_584, [0, 1, 0, 1], value=0)
|
457 |
+
t_585 = self.n_Conv_98(t_584_padded)
|
458 |
+
t_586 = F.relu(t_585)
|
459 |
+
t_587 = self.n_Conv_99(t_586)
|
460 |
+
t_588 = self.n_Conv_100(t_582)
|
461 |
+
t_589 = torch.add(t_587, t_588)
|
462 |
+
t_590 = F.relu(t_589)
|
463 |
+
t_591 = self.n_Conv_101(t_590)
|
464 |
+
t_592 = F.relu(t_591)
|
465 |
+
t_592_padded = F.pad(t_592, [1, 1, 1, 1], value=0)
|
466 |
+
t_593 = self.n_Conv_102(t_592_padded)
|
467 |
+
t_594 = F.relu(t_593)
|
468 |
+
t_595 = self.n_Conv_103(t_594)
|
469 |
+
t_596 = torch.add(t_595, t_590)
|
470 |
+
t_597 = F.relu(t_596)
|
471 |
+
t_598 = self.n_Conv_104(t_597)
|
472 |
+
t_599 = F.relu(t_598)
|
473 |
+
t_599_padded = F.pad(t_599, [1, 1, 1, 1], value=0)
|
474 |
+
t_600 = self.n_Conv_105(t_599_padded)
|
475 |
+
t_601 = F.relu(t_600)
|
476 |
+
t_602 = self.n_Conv_106(t_601)
|
477 |
+
t_603 = torch.add(t_602, t_597)
|
478 |
+
t_604 = F.relu(t_603)
|
479 |
+
t_605 = self.n_Conv_107(t_604)
|
480 |
+
t_606 = F.relu(t_605)
|
481 |
+
t_606_padded = F.pad(t_606, [1, 1, 1, 1], value=0)
|
482 |
+
t_607 = self.n_Conv_108(t_606_padded)
|
483 |
+
t_608 = F.relu(t_607)
|
484 |
+
t_609 = self.n_Conv_109(t_608)
|
485 |
+
t_610 = torch.add(t_609, t_604)
|
486 |
+
t_611 = F.relu(t_610)
|
487 |
+
t_612 = self.n_Conv_110(t_611)
|
488 |
+
t_613 = F.relu(t_612)
|
489 |
+
t_613_padded = F.pad(t_613, [1, 1, 1, 1], value=0)
|
490 |
+
t_614 = self.n_Conv_111(t_613_padded)
|
491 |
+
t_615 = F.relu(t_614)
|
492 |
+
t_616 = self.n_Conv_112(t_615)
|
493 |
+
t_617 = torch.add(t_616, t_611)
|
494 |
+
t_618 = F.relu(t_617)
|
495 |
+
t_619 = self.n_Conv_113(t_618)
|
496 |
+
t_620 = F.relu(t_619)
|
497 |
+
t_620_padded = F.pad(t_620, [1, 1, 1, 1], value=0)
|
498 |
+
t_621 = self.n_Conv_114(t_620_padded)
|
499 |
+
t_622 = F.relu(t_621)
|
500 |
+
t_623 = self.n_Conv_115(t_622)
|
501 |
+
t_624 = torch.add(t_623, t_618)
|
502 |
+
t_625 = F.relu(t_624)
|
503 |
+
t_626 = self.n_Conv_116(t_625)
|
504 |
+
t_627 = F.relu(t_626)
|
505 |
+
t_627_padded = F.pad(t_627, [1, 1, 1, 1], value=0)
|
506 |
+
t_628 = self.n_Conv_117(t_627_padded)
|
507 |
+
t_629 = F.relu(t_628)
|
508 |
+
t_630 = self.n_Conv_118(t_629)
|
509 |
+
t_631 = torch.add(t_630, t_625)
|
510 |
+
t_632 = F.relu(t_631)
|
511 |
+
t_633 = self.n_Conv_119(t_632)
|
512 |
+
t_634 = F.relu(t_633)
|
513 |
+
t_634_padded = F.pad(t_634, [1, 1, 1, 1], value=0)
|
514 |
+
t_635 = self.n_Conv_120(t_634_padded)
|
515 |
+
t_636 = F.relu(t_635)
|
516 |
+
t_637 = self.n_Conv_121(t_636)
|
517 |
+
t_638 = torch.add(t_637, t_632)
|
518 |
+
t_639 = F.relu(t_638)
|
519 |
+
t_640 = self.n_Conv_122(t_639)
|
520 |
+
t_641 = F.relu(t_640)
|
521 |
+
t_641_padded = F.pad(t_641, [1, 1, 1, 1], value=0)
|
522 |
+
t_642 = self.n_Conv_123(t_641_padded)
|
523 |
+
t_643 = F.relu(t_642)
|
524 |
+
t_644 = self.n_Conv_124(t_643)
|
525 |
+
t_645 = torch.add(t_644, t_639)
|
526 |
+
t_646 = F.relu(t_645)
|
527 |
+
t_647 = self.n_Conv_125(t_646)
|
528 |
+
t_648 = F.relu(t_647)
|
529 |
+
t_648_padded = F.pad(t_648, [1, 1, 1, 1], value=0)
|
530 |
+
t_649 = self.n_Conv_126(t_648_padded)
|
531 |
+
t_650 = F.relu(t_649)
|
532 |
+
t_651 = self.n_Conv_127(t_650)
|
533 |
+
t_652 = torch.add(t_651, t_646)
|
534 |
+
t_653 = F.relu(t_652)
|
535 |
+
t_654 = self.n_Conv_128(t_653)
|
536 |
+
t_655 = F.relu(t_654)
|
537 |
+
t_655_padded = F.pad(t_655, [1, 1, 1, 1], value=0)
|
538 |
+
t_656 = self.n_Conv_129(t_655_padded)
|
539 |
+
t_657 = F.relu(t_656)
|
540 |
+
t_658 = self.n_Conv_130(t_657)
|
541 |
+
t_659 = torch.add(t_658, t_653)
|
542 |
+
t_660 = F.relu(t_659)
|
543 |
+
t_661 = self.n_Conv_131(t_660)
|
544 |
+
t_662 = F.relu(t_661)
|
545 |
+
t_662_padded = F.pad(t_662, [1, 1, 1, 1], value=0)
|
546 |
+
t_663 = self.n_Conv_132(t_662_padded)
|
547 |
+
t_664 = F.relu(t_663)
|
548 |
+
t_665 = self.n_Conv_133(t_664)
|
549 |
+
t_666 = torch.add(t_665, t_660)
|
550 |
+
t_667 = F.relu(t_666)
|
551 |
+
t_668 = self.n_Conv_134(t_667)
|
552 |
+
t_669 = F.relu(t_668)
|
553 |
+
t_669_padded = F.pad(t_669, [1, 1, 1, 1], value=0)
|
554 |
+
t_670 = self.n_Conv_135(t_669_padded)
|
555 |
+
t_671 = F.relu(t_670)
|
556 |
+
t_672 = self.n_Conv_136(t_671)
|
557 |
+
t_673 = torch.add(t_672, t_667)
|
558 |
+
t_674 = F.relu(t_673)
|
559 |
+
t_675 = self.n_Conv_137(t_674)
|
560 |
+
t_676 = F.relu(t_675)
|
561 |
+
t_676_padded = F.pad(t_676, [1, 1, 1, 1], value=0)
|
562 |
+
t_677 = self.n_Conv_138(t_676_padded)
|
563 |
+
t_678 = F.relu(t_677)
|
564 |
+
t_679 = self.n_Conv_139(t_678)
|
565 |
+
t_680 = torch.add(t_679, t_674)
|
566 |
+
t_681 = F.relu(t_680)
|
567 |
+
t_682 = self.n_Conv_140(t_681)
|
568 |
+
t_683 = F.relu(t_682)
|
569 |
+
t_683_padded = F.pad(t_683, [1, 1, 1, 1], value=0)
|
570 |
+
t_684 = self.n_Conv_141(t_683_padded)
|
571 |
+
t_685 = F.relu(t_684)
|
572 |
+
t_686 = self.n_Conv_142(t_685)
|
573 |
+
t_687 = torch.add(t_686, t_681)
|
574 |
+
t_688 = F.relu(t_687)
|
575 |
+
t_689 = self.n_Conv_143(t_688)
|
576 |
+
t_690 = F.relu(t_689)
|
577 |
+
t_690_padded = F.pad(t_690, [1, 1, 1, 1], value=0)
|
578 |
+
t_691 = self.n_Conv_144(t_690_padded)
|
579 |
+
t_692 = F.relu(t_691)
|
580 |
+
t_693 = self.n_Conv_145(t_692)
|
581 |
+
t_694 = torch.add(t_693, t_688)
|
582 |
+
t_695 = F.relu(t_694)
|
583 |
+
t_696 = self.n_Conv_146(t_695)
|
584 |
+
t_697 = F.relu(t_696)
|
585 |
+
t_697_padded = F.pad(t_697, [1, 1, 1, 1], value=0)
|
586 |
+
t_698 = self.n_Conv_147(t_697_padded)
|
587 |
+
t_699 = F.relu(t_698)
|
588 |
+
t_700 = self.n_Conv_148(t_699)
|
589 |
+
t_701 = torch.add(t_700, t_695)
|
590 |
+
t_702 = F.relu(t_701)
|
591 |
+
t_703 = self.n_Conv_149(t_702)
|
592 |
+
t_704 = F.relu(t_703)
|
593 |
+
t_704_padded = F.pad(t_704, [1, 1, 1, 1], value=0)
|
594 |
+
t_705 = self.n_Conv_150(t_704_padded)
|
595 |
+
t_706 = F.relu(t_705)
|
596 |
+
t_707 = self.n_Conv_151(t_706)
|
597 |
+
t_708 = torch.add(t_707, t_702)
|
598 |
+
t_709 = F.relu(t_708)
|
599 |
+
t_710 = self.n_Conv_152(t_709)
|
600 |
+
t_711 = F.relu(t_710)
|
601 |
+
t_711_padded = F.pad(t_711, [1, 1, 1, 1], value=0)
|
602 |
+
t_712 = self.n_Conv_153(t_711_padded)
|
603 |
+
t_713 = F.relu(t_712)
|
604 |
+
t_714 = self.n_Conv_154(t_713)
|
605 |
+
t_715 = torch.add(t_714, t_709)
|
606 |
+
t_716 = F.relu(t_715)
|
607 |
+
t_717 = self.n_Conv_155(t_716)
|
608 |
+
t_718 = F.relu(t_717)
|
609 |
+
t_718_padded = F.pad(t_718, [1, 1, 1, 1], value=0)
|
610 |
+
t_719 = self.n_Conv_156(t_718_padded)
|
611 |
+
t_720 = F.relu(t_719)
|
612 |
+
t_721 = self.n_Conv_157(t_720)
|
613 |
+
t_722 = torch.add(t_721, t_716)
|
614 |
+
t_723 = F.relu(t_722)
|
615 |
+
t_724 = self.n_Conv_158(t_723)
|
616 |
+
t_725 = self.n_Conv_159(t_723)
|
617 |
+
t_726 = F.relu(t_725)
|
618 |
+
t_726_padded = F.pad(t_726, [0, 1, 0, 1], value=0)
|
619 |
+
t_727 = self.n_Conv_160(t_726_padded)
|
620 |
+
t_728 = F.relu(t_727)
|
621 |
+
t_729 = self.n_Conv_161(t_728)
|
622 |
+
t_730 = torch.add(t_729, t_724)
|
623 |
+
t_731 = F.relu(t_730)
|
624 |
+
t_732 = self.n_Conv_162(t_731)
|
625 |
+
t_733 = F.relu(t_732)
|
626 |
+
t_733_padded = F.pad(t_733, [1, 1, 1, 1], value=0)
|
627 |
+
t_734 = self.n_Conv_163(t_733_padded)
|
628 |
+
t_735 = F.relu(t_734)
|
629 |
+
t_736 = self.n_Conv_164(t_735)
|
630 |
+
t_737 = torch.add(t_736, t_731)
|
631 |
+
t_738 = F.relu(t_737)
|
632 |
+
t_739 = self.n_Conv_165(t_738)
|
633 |
+
t_740 = F.relu(t_739)
|
634 |
+
t_740_padded = F.pad(t_740, [1, 1, 1, 1], value=0)
|
635 |
+
t_741 = self.n_Conv_166(t_740_padded)
|
636 |
+
t_742 = F.relu(t_741)
|
637 |
+
t_743 = self.n_Conv_167(t_742)
|
638 |
+
t_744 = torch.add(t_743, t_738)
|
639 |
+
t_745 = F.relu(t_744)
|
640 |
+
t_746 = self.n_Conv_168(t_745)
|
641 |
+
t_747 = self.n_Conv_169(t_745)
|
642 |
+
t_748 = F.relu(t_747)
|
643 |
+
t_748_padded = F.pad(t_748, [0, 1, 0, 1], value=0)
|
644 |
+
t_749 = self.n_Conv_170(t_748_padded)
|
645 |
+
t_750 = F.relu(t_749)
|
646 |
+
t_751 = self.n_Conv_171(t_750)
|
647 |
+
t_752 = torch.add(t_751, t_746)
|
648 |
+
t_753 = F.relu(t_752)
|
649 |
+
t_754 = self.n_Conv_172(t_753)
|
650 |
+
t_755 = F.relu(t_754)
|
651 |
+
t_755_padded = F.pad(t_755, [1, 1, 1, 1], value=0)
|
652 |
+
t_756 = self.n_Conv_173(t_755_padded)
|
653 |
+
t_757 = F.relu(t_756)
|
654 |
+
t_758 = self.n_Conv_174(t_757)
|
655 |
+
t_759 = torch.add(t_758, t_753)
|
656 |
+
t_760 = F.relu(t_759)
|
657 |
+
t_761 = self.n_Conv_175(t_760)
|
658 |
+
t_762 = F.relu(t_761)
|
659 |
+
t_762_padded = F.pad(t_762, [1, 1, 1, 1], value=0)
|
660 |
+
t_763 = self.n_Conv_176(t_762_padded)
|
661 |
+
t_764 = F.relu(t_763)
|
662 |
+
t_765 = self.n_Conv_177(t_764)
|
663 |
+
t_766 = torch.add(t_765, t_760)
|
664 |
+
t_767 = F.relu(t_766)
|
665 |
+
t_768 = self.n_Conv_178(t_767)
|
666 |
+
t_769 = F.avg_pool2d(t_768, kernel_size=t_768.shape[-2:])
|
667 |
+
t_770 = torch.squeeze(t_769, 3)
|
668 |
+
t_770 = torch.squeeze(t_770, 2)
|
669 |
+
t_771 = torch.sigmoid(t_770)
|
670 |
+
return t_771
|
671 |
+
|
672 |
+
def load_state_dict(self, state_dict, **kwargs):
|
673 |
+
self.tags = state_dict.get('tags', [])
|
674 |
+
|
675 |
+
super(DeepDanbooruModel, self).load_state_dict({k: v for k, v in state_dict.items() if k != 'tags'})
|
676 |
+
|
stable-diffusion-webui-master/modules/devices.py
ADDED
@@ -0,0 +1,124 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import sys, os, shlex
|
2 |
+
import contextlib
|
3 |
+
import torch
|
4 |
+
from modules import errors
|
5 |
+
from packaging import version
|
6 |
+
|
7 |
+
|
8 |
+
# has_mps is only available in nightly pytorch (for now) and macOS 12.3+.
|
9 |
+
# check `getattr` and try it for compatibility
|
10 |
+
def has_mps() -> bool:
|
11 |
+
if not getattr(torch, 'has_mps', False):
|
12 |
+
return False
|
13 |
+
try:
|
14 |
+
torch.zeros(1).to(torch.device("mps"))
|
15 |
+
return True
|
16 |
+
except Exception:
|
17 |
+
return False
|
18 |
+
|
19 |
+
|
20 |
+
def extract_device_id(args, name):
|
21 |
+
for x in range(len(args)):
|
22 |
+
if name in args[x]:
|
23 |
+
return args[x + 1]
|
24 |
+
|
25 |
+
return None
|
26 |
+
|
27 |
+
|
28 |
+
def get_cuda_device_string():
|
29 |
+
from modules import shared
|
30 |
+
|
31 |
+
if shared.cmd_opts.device_id is not None:
|
32 |
+
return f"cuda:{shared.cmd_opts.device_id}"
|
33 |
+
|
34 |
+
return "cuda"
|
35 |
+
|
36 |
+
|
37 |
+
def get_optimal_device():
|
38 |
+
if torch.cuda.is_available():
|
39 |
+
return torch.device(get_cuda_device_string())
|
40 |
+
|
41 |
+
if has_mps():
|
42 |
+
return torch.device("mps")
|
43 |
+
|
44 |
+
return cpu
|
45 |
+
|
46 |
+
|
47 |
+
def torch_gc():
|
48 |
+
if torch.cuda.is_available():
|
49 |
+
with torch.cuda.device(get_cuda_device_string()):
|
50 |
+
torch.cuda.empty_cache()
|
51 |
+
torch.cuda.ipc_collect()
|
52 |
+
|
53 |
+
|
54 |
+
def enable_tf32():
|
55 |
+
if torch.cuda.is_available():
|
56 |
+
torch.backends.cuda.matmul.allow_tf32 = True
|
57 |
+
torch.backends.cudnn.allow_tf32 = True
|
58 |
+
|
59 |
+
|
60 |
+
errors.run(enable_tf32, "Enabling TF32")
|
61 |
+
|
62 |
+
cpu = torch.device("cpu")
|
63 |
+
device = device_interrogate = device_gfpgan = device_swinir = device_esrgan = device_scunet = device_codeformer = None
|
64 |
+
dtype = torch.float16
|
65 |
+
dtype_vae = torch.float16
|
66 |
+
|
67 |
+
|
68 |
+
def randn(seed, shape):
|
69 |
+
# Pytorch currently doesn't handle setting randomness correctly when the metal backend is used.
|
70 |
+
if device.type == 'mps':
|
71 |
+
generator = torch.Generator(device=cpu)
|
72 |
+
generator.manual_seed(seed)
|
73 |
+
noise = torch.randn(shape, generator=generator, device=cpu).to(device)
|
74 |
+
return noise
|
75 |
+
|
76 |
+
torch.manual_seed(seed)
|
77 |
+
return torch.randn(shape, device=device)
|
78 |
+
|
79 |
+
|
80 |
+
def randn_without_seed(shape):
|
81 |
+
# Pytorch currently doesn't handle setting randomness correctly when the metal backend is used.
|
82 |
+
if device.type == 'mps':
|
83 |
+
generator = torch.Generator(device=cpu)
|
84 |
+
noise = torch.randn(shape, generator=generator, device=cpu).to(device)
|
85 |
+
return noise
|
86 |
+
|
87 |
+
return torch.randn(shape, device=device)
|
88 |
+
|
89 |
+
|
90 |
+
def autocast(disable=False):
|
91 |
+
from modules import shared
|
92 |
+
|
93 |
+
if disable:
|
94 |
+
return contextlib.nullcontext()
|
95 |
+
|
96 |
+
if dtype == torch.float32 or shared.cmd_opts.precision == "full":
|
97 |
+
return contextlib.nullcontext()
|
98 |
+
|
99 |
+
return torch.autocast("cuda")
|
100 |
+
|
101 |
+
|
102 |
+
# MPS workaround for https://github.com/pytorch/pytorch/issues/79383
|
103 |
+
orig_tensor_to = torch.Tensor.to
|
104 |
+
def tensor_to_fix(self, *args, **kwargs):
|
105 |
+
if self.device.type != 'mps' and \
|
106 |
+
((len(args) > 0 and isinstance(args[0], torch.device) and args[0].type == 'mps') or \
|
107 |
+
(isinstance(kwargs.get('device'), torch.device) and kwargs['device'].type == 'mps')):
|
108 |
+
self = self.contiguous()
|
109 |
+
return orig_tensor_to(self, *args, **kwargs)
|
110 |
+
|
111 |
+
|
112 |
+
# MPS workaround for https://github.com/pytorch/pytorch/issues/80800
|
113 |
+
orig_layer_norm = torch.nn.functional.layer_norm
|
114 |
+
def layer_norm_fix(*args, **kwargs):
|
115 |
+
if len(args) > 0 and isinstance(args[0], torch.Tensor) and args[0].device.type == 'mps':
|
116 |
+
args = list(args)
|
117 |
+
args[0] = args[0].contiguous()
|
118 |
+
return orig_layer_norm(*args, **kwargs)
|
119 |
+
|
120 |
+
|
121 |
+
# PyTorch 1.13 doesn't need these fixes but unfortunately is slower and has regressions that prevent training from working
|
122 |
+
if has_mps() and version.parse(torch.__version__) < version.parse("1.13"):
|
123 |
+
torch.Tensor.to = tensor_to_fix
|
124 |
+
torch.nn.functional.layer_norm = layer_norm_fix
|
stable-diffusion-webui-master/modules/errors.py
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import sys
|
2 |
+
import traceback
|
3 |
+
|
4 |
+
|
5 |
+
def run(code, task):
|
6 |
+
try:
|
7 |
+
code()
|
8 |
+
except Exception as e:
|
9 |
+
print(f"{task}: {type(e).__name__}", file=sys.stderr)
|
10 |
+
print(traceback.format_exc(), file=sys.stderr)
|
stable-diffusion-webui-master/modules/esrgan_model.py
ADDED
@@ -0,0 +1,233 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
|
3 |
+
import numpy as np
|
4 |
+
import torch
|
5 |
+
from PIL import Image
|
6 |
+
from basicsr.utils.download_util import load_file_from_url
|
7 |
+
|
8 |
+
import modules.esrgan_model_arch as arch
|
9 |
+
from modules import shared, modelloader, images, devices
|
10 |
+
from modules.upscaler import Upscaler, UpscalerData
|
11 |
+
from modules.shared import opts
|
12 |
+
|
13 |
+
|
14 |
+
|
15 |
+
def mod2normal(state_dict):
|
16 |
+
# this code is copied from https://github.com/victorca25/iNNfer
|
17 |
+
if 'conv_first.weight' in state_dict:
|
18 |
+
crt_net = {}
|
19 |
+
items = []
|
20 |
+
for k, v in state_dict.items():
|
21 |
+
items.append(k)
|
22 |
+
|
23 |
+
crt_net['model.0.weight'] = state_dict['conv_first.weight']
|
24 |
+
crt_net['model.0.bias'] = state_dict['conv_first.bias']
|
25 |
+
|
26 |
+
for k in items.copy():
|
27 |
+
if 'RDB' in k:
|
28 |
+
ori_k = k.replace('RRDB_trunk.', 'model.1.sub.')
|
29 |
+
if '.weight' in k:
|
30 |
+
ori_k = ori_k.replace('.weight', '.0.weight')
|
31 |
+
elif '.bias' in k:
|
32 |
+
ori_k = ori_k.replace('.bias', '.0.bias')
|
33 |
+
crt_net[ori_k] = state_dict[k]
|
34 |
+
items.remove(k)
|
35 |
+
|
36 |
+
crt_net['model.1.sub.23.weight'] = state_dict['trunk_conv.weight']
|
37 |
+
crt_net['model.1.sub.23.bias'] = state_dict['trunk_conv.bias']
|
38 |
+
crt_net['model.3.weight'] = state_dict['upconv1.weight']
|
39 |
+
crt_net['model.3.bias'] = state_dict['upconv1.bias']
|
40 |
+
crt_net['model.6.weight'] = state_dict['upconv2.weight']
|
41 |
+
crt_net['model.6.bias'] = state_dict['upconv2.bias']
|
42 |
+
crt_net['model.8.weight'] = state_dict['HRconv.weight']
|
43 |
+
crt_net['model.8.bias'] = state_dict['HRconv.bias']
|
44 |
+
crt_net['model.10.weight'] = state_dict['conv_last.weight']
|
45 |
+
crt_net['model.10.bias'] = state_dict['conv_last.bias']
|
46 |
+
state_dict = crt_net
|
47 |
+
return state_dict
|
48 |
+
|
49 |
+
|
50 |
+
def resrgan2normal(state_dict, nb=23):
|
51 |
+
# this code is copied from https://github.com/victorca25/iNNfer
|
52 |
+
if "conv_first.weight" in state_dict and "body.0.rdb1.conv1.weight" in state_dict:
|
53 |
+
re8x = 0
|
54 |
+
crt_net = {}
|
55 |
+
items = []
|
56 |
+
for k, v in state_dict.items():
|
57 |
+
items.append(k)
|
58 |
+
|
59 |
+
crt_net['model.0.weight'] = state_dict['conv_first.weight']
|
60 |
+
crt_net['model.0.bias'] = state_dict['conv_first.bias']
|
61 |
+
|
62 |
+
for k in items.copy():
|
63 |
+
if "rdb" in k:
|
64 |
+
ori_k = k.replace('body.', 'model.1.sub.')
|
65 |
+
ori_k = ori_k.replace('.rdb', '.RDB')
|
66 |
+
if '.weight' in k:
|
67 |
+
ori_k = ori_k.replace('.weight', '.0.weight')
|
68 |
+
elif '.bias' in k:
|
69 |
+
ori_k = ori_k.replace('.bias', '.0.bias')
|
70 |
+
crt_net[ori_k] = state_dict[k]
|
71 |
+
items.remove(k)
|
72 |
+
|
73 |
+
crt_net[f'model.1.sub.{nb}.weight'] = state_dict['conv_body.weight']
|
74 |
+
crt_net[f'model.1.sub.{nb}.bias'] = state_dict['conv_body.bias']
|
75 |
+
crt_net['model.3.weight'] = state_dict['conv_up1.weight']
|
76 |
+
crt_net['model.3.bias'] = state_dict['conv_up1.bias']
|
77 |
+
crt_net['model.6.weight'] = state_dict['conv_up2.weight']
|
78 |
+
crt_net['model.6.bias'] = state_dict['conv_up2.bias']
|
79 |
+
|
80 |
+
if 'conv_up3.weight' in state_dict:
|
81 |
+
# modification supporting: https://github.com/ai-forever/Real-ESRGAN/blob/main/RealESRGAN/rrdbnet_arch.py
|
82 |
+
re8x = 3
|
83 |
+
crt_net['model.9.weight'] = state_dict['conv_up3.weight']
|
84 |
+
crt_net['model.9.bias'] = state_dict['conv_up3.bias']
|
85 |
+
|
86 |
+
crt_net[f'model.{8+re8x}.weight'] = state_dict['conv_hr.weight']
|
87 |
+
crt_net[f'model.{8+re8x}.bias'] = state_dict['conv_hr.bias']
|
88 |
+
crt_net[f'model.{10+re8x}.weight'] = state_dict['conv_last.weight']
|
89 |
+
crt_net[f'model.{10+re8x}.bias'] = state_dict['conv_last.bias']
|
90 |
+
|
91 |
+
state_dict = crt_net
|
92 |
+
return state_dict
|
93 |
+
|
94 |
+
|
95 |
+
def infer_params(state_dict):
|
96 |
+
# this code is copied from https://github.com/victorca25/iNNfer
|
97 |
+
scale2x = 0
|
98 |
+
scalemin = 6
|
99 |
+
n_uplayer = 0
|
100 |
+
plus = False
|
101 |
+
|
102 |
+
for block in list(state_dict):
|
103 |
+
parts = block.split(".")
|
104 |
+
n_parts = len(parts)
|
105 |
+
if n_parts == 5 and parts[2] == "sub":
|
106 |
+
nb = int(parts[3])
|
107 |
+
elif n_parts == 3:
|
108 |
+
part_num = int(parts[1])
|
109 |
+
if (part_num > scalemin
|
110 |
+
and parts[0] == "model"
|
111 |
+
and parts[2] == "weight"):
|
112 |
+
scale2x += 1
|
113 |
+
if part_num > n_uplayer:
|
114 |
+
n_uplayer = part_num
|
115 |
+
out_nc = state_dict[block].shape[0]
|
116 |
+
if not plus and "conv1x1" in block:
|
117 |
+
plus = True
|
118 |
+
|
119 |
+
nf = state_dict["model.0.weight"].shape[0]
|
120 |
+
in_nc = state_dict["model.0.weight"].shape[1]
|
121 |
+
out_nc = out_nc
|
122 |
+
scale = 2 ** scale2x
|
123 |
+
|
124 |
+
return in_nc, out_nc, nf, nb, plus, scale
|
125 |
+
|
126 |
+
|
127 |
+
class UpscalerESRGAN(Upscaler):
|
128 |
+
def __init__(self, dirname):
|
129 |
+
self.name = "ESRGAN"
|
130 |
+
self.model_url = "https://github.com/cszn/KAIR/releases/download/v1.0/ESRGAN.pth"
|
131 |
+
self.model_name = "ESRGAN_4x"
|
132 |
+
self.scalers = []
|
133 |
+
self.user_path = dirname
|
134 |
+
super().__init__()
|
135 |
+
model_paths = self.find_models(ext_filter=[".pt", ".pth"])
|
136 |
+
scalers = []
|
137 |
+
if len(model_paths) == 0:
|
138 |
+
scaler_data = UpscalerData(self.model_name, self.model_url, self, 4)
|
139 |
+
scalers.append(scaler_data)
|
140 |
+
for file in model_paths:
|
141 |
+
if "http" in file:
|
142 |
+
name = self.model_name
|
143 |
+
else:
|
144 |
+
name = modelloader.friendly_name(file)
|
145 |
+
|
146 |
+
scaler_data = UpscalerData(name, file, self, 4)
|
147 |
+
self.scalers.append(scaler_data)
|
148 |
+
|
149 |
+
def do_upscale(self, img, selected_model):
|
150 |
+
model = self.load_model(selected_model)
|
151 |
+
if model is None:
|
152 |
+
return img
|
153 |
+
model.to(devices.device_esrgan)
|
154 |
+
img = esrgan_upscale(model, img)
|
155 |
+
return img
|
156 |
+
|
157 |
+
def load_model(self, path: str):
|
158 |
+
if "http" in path:
|
159 |
+
filename = load_file_from_url(url=self.model_url, model_dir=self.model_path,
|
160 |
+
file_name="%s.pth" % self.model_name,
|
161 |
+
progress=True)
|
162 |
+
else:
|
163 |
+
filename = path
|
164 |
+
if not os.path.exists(filename) or filename is None:
|
165 |
+
print("Unable to load %s from %s" % (self.model_path, filename))
|
166 |
+
return None
|
167 |
+
|
168 |
+
state_dict = torch.load(filename, map_location='cpu' if devices.device_esrgan.type == 'mps' else None)
|
169 |
+
|
170 |
+
if "params_ema" in state_dict:
|
171 |
+
state_dict = state_dict["params_ema"]
|
172 |
+
elif "params" in state_dict:
|
173 |
+
state_dict = state_dict["params"]
|
174 |
+
num_conv = 16 if "realesr-animevideov3" in filename else 32
|
175 |
+
model = arch.SRVGGNetCompact(num_in_ch=3, num_out_ch=3, num_feat=64, num_conv=num_conv, upscale=4, act_type='prelu')
|
176 |
+
model.load_state_dict(state_dict)
|
177 |
+
model.eval()
|
178 |
+
return model
|
179 |
+
|
180 |
+
if "body.0.rdb1.conv1.weight" in state_dict and "conv_first.weight" in state_dict:
|
181 |
+
nb = 6 if "RealESRGAN_x4plus_anime_6B" in filename else 23
|
182 |
+
state_dict = resrgan2normal(state_dict, nb)
|
183 |
+
elif "conv_first.weight" in state_dict:
|
184 |
+
state_dict = mod2normal(state_dict)
|
185 |
+
elif "model.0.weight" not in state_dict:
|
186 |
+
raise Exception("The file is not a recognized ESRGAN model.")
|
187 |
+
|
188 |
+
in_nc, out_nc, nf, nb, plus, mscale = infer_params(state_dict)
|
189 |
+
|
190 |
+
model = arch.RRDBNet(in_nc=in_nc, out_nc=out_nc, nf=nf, nb=nb, upscale=mscale, plus=plus)
|
191 |
+
model.load_state_dict(state_dict)
|
192 |
+
model.eval()
|
193 |
+
|
194 |
+
return model
|
195 |
+
|
196 |
+
|
197 |
+
def upscale_without_tiling(model, img):
|
198 |
+
img = np.array(img)
|
199 |
+
img = img[:, :, ::-1]
|
200 |
+
img = np.ascontiguousarray(np.transpose(img, (2, 0, 1))) / 255
|
201 |
+
img = torch.from_numpy(img).float()
|
202 |
+
img = img.unsqueeze(0).to(devices.device_esrgan)
|
203 |
+
with torch.no_grad():
|
204 |
+
output = model(img)
|
205 |
+
output = output.squeeze().float().cpu().clamp_(0, 1).numpy()
|
206 |
+
output = 255. * np.moveaxis(output, 0, 2)
|
207 |
+
output = output.astype(np.uint8)
|
208 |
+
output = output[:, :, ::-1]
|
209 |
+
return Image.fromarray(output, 'RGB')
|
210 |
+
|
211 |
+
|
212 |
+
def esrgan_upscale(model, img):
|
213 |
+
if opts.ESRGAN_tile == 0:
|
214 |
+
return upscale_without_tiling(model, img)
|
215 |
+
|
216 |
+
grid = images.split_grid(img, opts.ESRGAN_tile, opts.ESRGAN_tile, opts.ESRGAN_tile_overlap)
|
217 |
+
newtiles = []
|
218 |
+
scale_factor = 1
|
219 |
+
|
220 |
+
for y, h, row in grid.tiles:
|
221 |
+
newrow = []
|
222 |
+
for tiledata in row:
|
223 |
+
x, w, tile = tiledata
|
224 |
+
|
225 |
+
output = upscale_without_tiling(model, tile)
|
226 |
+
scale_factor = output.width // tile.width
|
227 |
+
|
228 |
+
newrow.append([x * scale_factor, w * scale_factor, output])
|
229 |
+
newtiles.append([y * scale_factor, h * scale_factor, newrow])
|
230 |
+
|
231 |
+
newgrid = images.Grid(newtiles, grid.tile_w * scale_factor, grid.tile_h * scale_factor, grid.image_w * scale_factor, grid.image_h * scale_factor, grid.overlap * scale_factor)
|
232 |
+
output = images.combine_grid(newgrid)
|
233 |
+
return output
|
stable-diffusion-webui-master/modules/esrgan_model_arch.py
ADDED
@@ -0,0 +1,463 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# this file is adapted from https://github.com/victorca25/iNNfer
|
2 |
+
|
3 |
+
import math
|
4 |
+
import functools
|
5 |
+
import torch
|
6 |
+
import torch.nn as nn
|
7 |
+
import torch.nn.functional as F
|
8 |
+
|
9 |
+
|
10 |
+
####################
|
11 |
+
# RRDBNet Generator
|
12 |
+
####################
|
13 |
+
|
14 |
+
class RRDBNet(nn.Module):
|
15 |
+
def __init__(self, in_nc, out_nc, nf, nb, nr=3, gc=32, upscale=4, norm_type=None,
|
16 |
+
act_type='leakyrelu', mode='CNA', upsample_mode='upconv', convtype='Conv2D',
|
17 |
+
finalact=None, gaussian_noise=False, plus=False):
|
18 |
+
super(RRDBNet, self).__init__()
|
19 |
+
n_upscale = int(math.log(upscale, 2))
|
20 |
+
if upscale == 3:
|
21 |
+
n_upscale = 1
|
22 |
+
|
23 |
+
self.resrgan_scale = 0
|
24 |
+
if in_nc % 16 == 0:
|
25 |
+
self.resrgan_scale = 1
|
26 |
+
elif in_nc != 4 and in_nc % 4 == 0:
|
27 |
+
self.resrgan_scale = 2
|
28 |
+
|
29 |
+
fea_conv = conv_block(in_nc, nf, kernel_size=3, norm_type=None, act_type=None, convtype=convtype)
|
30 |
+
rb_blocks = [RRDB(nf, nr, kernel_size=3, gc=32, stride=1, bias=1, pad_type='zero',
|
31 |
+
norm_type=norm_type, act_type=act_type, mode='CNA', convtype=convtype,
|
32 |
+
gaussian_noise=gaussian_noise, plus=plus) for _ in range(nb)]
|
33 |
+
LR_conv = conv_block(nf, nf, kernel_size=3, norm_type=norm_type, act_type=None, mode=mode, convtype=convtype)
|
34 |
+
|
35 |
+
if upsample_mode == 'upconv':
|
36 |
+
upsample_block = upconv_block
|
37 |
+
elif upsample_mode == 'pixelshuffle':
|
38 |
+
upsample_block = pixelshuffle_block
|
39 |
+
else:
|
40 |
+
raise NotImplementedError('upsample mode [{:s}] is not found'.format(upsample_mode))
|
41 |
+
if upscale == 3:
|
42 |
+
upsampler = upsample_block(nf, nf, 3, act_type=act_type, convtype=convtype)
|
43 |
+
else:
|
44 |
+
upsampler = [upsample_block(nf, nf, act_type=act_type, convtype=convtype) for _ in range(n_upscale)]
|
45 |
+
HR_conv0 = conv_block(nf, nf, kernel_size=3, norm_type=None, act_type=act_type, convtype=convtype)
|
46 |
+
HR_conv1 = conv_block(nf, out_nc, kernel_size=3, norm_type=None, act_type=None, convtype=convtype)
|
47 |
+
|
48 |
+
outact = act(finalact) if finalact else None
|
49 |
+
|
50 |
+
self.model = sequential(fea_conv, ShortcutBlock(sequential(*rb_blocks, LR_conv)),
|
51 |
+
*upsampler, HR_conv0, HR_conv1, outact)
|
52 |
+
|
53 |
+
def forward(self, x, outm=None):
|
54 |
+
if self.resrgan_scale == 1:
|
55 |
+
feat = pixel_unshuffle(x, scale=4)
|
56 |
+
elif self.resrgan_scale == 2:
|
57 |
+
feat = pixel_unshuffle(x, scale=2)
|
58 |
+
else:
|
59 |
+
feat = x
|
60 |
+
|
61 |
+
return self.model(feat)
|
62 |
+
|
63 |
+
|
64 |
+
class RRDB(nn.Module):
|
65 |
+
"""
|
66 |
+
Residual in Residual Dense Block
|
67 |
+
(ESRGAN: Enhanced Super-Resolution Generative Adversarial Networks)
|
68 |
+
"""
|
69 |
+
|
70 |
+
def __init__(self, nf, nr=3, kernel_size=3, gc=32, stride=1, bias=1, pad_type='zero',
|
71 |
+
norm_type=None, act_type='leakyrelu', mode='CNA', convtype='Conv2D',
|
72 |
+
spectral_norm=False, gaussian_noise=False, plus=False):
|
73 |
+
super(RRDB, self).__init__()
|
74 |
+
# This is for backwards compatibility with existing models
|
75 |
+
if nr == 3:
|
76 |
+
self.RDB1 = ResidualDenseBlock_5C(nf, kernel_size, gc, stride, bias, pad_type,
|
77 |
+
norm_type, act_type, mode, convtype, spectral_norm=spectral_norm,
|
78 |
+
gaussian_noise=gaussian_noise, plus=plus)
|
79 |
+
self.RDB2 = ResidualDenseBlock_5C(nf, kernel_size, gc, stride, bias, pad_type,
|
80 |
+
norm_type, act_type, mode, convtype, spectral_norm=spectral_norm,
|
81 |
+
gaussian_noise=gaussian_noise, plus=plus)
|
82 |
+
self.RDB3 = ResidualDenseBlock_5C(nf, kernel_size, gc, stride, bias, pad_type,
|
83 |
+
norm_type, act_type, mode, convtype, spectral_norm=spectral_norm,
|
84 |
+
gaussian_noise=gaussian_noise, plus=plus)
|
85 |
+
else:
|
86 |
+
RDB_list = [ResidualDenseBlock_5C(nf, kernel_size, gc, stride, bias, pad_type,
|
87 |
+
norm_type, act_type, mode, convtype, spectral_norm=spectral_norm,
|
88 |
+
gaussian_noise=gaussian_noise, plus=plus) for _ in range(nr)]
|
89 |
+
self.RDBs = nn.Sequential(*RDB_list)
|
90 |
+
|
91 |
+
def forward(self, x):
|
92 |
+
if hasattr(self, 'RDB1'):
|
93 |
+
out = self.RDB1(x)
|
94 |
+
out = self.RDB2(out)
|
95 |
+
out = self.RDB3(out)
|
96 |
+
else:
|
97 |
+
out = self.RDBs(x)
|
98 |
+
return out * 0.2 + x
|
99 |
+
|
100 |
+
|
101 |
+
class ResidualDenseBlock_5C(nn.Module):
|
102 |
+
"""
|
103 |
+
Residual Dense Block
|
104 |
+
The core module of paper: (Residual Dense Network for Image Super-Resolution, CVPR 18)
|
105 |
+
Modified options that can be used:
|
106 |
+
- "Partial Convolution based Padding" arXiv:1811.11718
|
107 |
+
- "Spectral normalization" arXiv:1802.05957
|
108 |
+
- "ICASSP 2020 - ESRGAN+ : Further Improving ESRGAN" N. C.
|
109 |
+
{Rakotonirina} and A. {Rasoanaivo}
|
110 |
+
"""
|
111 |
+
|
112 |
+
def __init__(self, nf=64, kernel_size=3, gc=32, stride=1, bias=1, pad_type='zero',
|
113 |
+
norm_type=None, act_type='leakyrelu', mode='CNA', convtype='Conv2D',
|
114 |
+
spectral_norm=False, gaussian_noise=False, plus=False):
|
115 |
+
super(ResidualDenseBlock_5C, self).__init__()
|
116 |
+
|
117 |
+
self.noise = GaussianNoise() if gaussian_noise else None
|
118 |
+
self.conv1x1 = conv1x1(nf, gc) if plus else None
|
119 |
+
|
120 |
+
self.conv1 = conv_block(nf, gc, kernel_size, stride, bias=bias, pad_type=pad_type,
|
121 |
+
norm_type=norm_type, act_type=act_type, mode=mode, convtype=convtype,
|
122 |
+
spectral_norm=spectral_norm)
|
123 |
+
self.conv2 = conv_block(nf+gc, gc, kernel_size, stride, bias=bias, pad_type=pad_type,
|
124 |
+
norm_type=norm_type, act_type=act_type, mode=mode, convtype=convtype,
|
125 |
+
spectral_norm=spectral_norm)
|
126 |
+
self.conv3 = conv_block(nf+2*gc, gc, kernel_size, stride, bias=bias, pad_type=pad_type,
|
127 |
+
norm_type=norm_type, act_type=act_type, mode=mode, convtype=convtype,
|
128 |
+
spectral_norm=spectral_norm)
|
129 |
+
self.conv4 = conv_block(nf+3*gc, gc, kernel_size, stride, bias=bias, pad_type=pad_type,
|
130 |
+
norm_type=norm_type, act_type=act_type, mode=mode, convtype=convtype,
|
131 |
+
spectral_norm=spectral_norm)
|
132 |
+
if mode == 'CNA':
|
133 |
+
last_act = None
|
134 |
+
else:
|
135 |
+
last_act = act_type
|
136 |
+
self.conv5 = conv_block(nf+4*gc, nf, 3, stride, bias=bias, pad_type=pad_type,
|
137 |
+
norm_type=norm_type, act_type=last_act, mode=mode, convtype=convtype,
|
138 |
+
spectral_norm=spectral_norm)
|
139 |
+
|
140 |
+
def forward(self, x):
|
141 |
+
x1 = self.conv1(x)
|
142 |
+
x2 = self.conv2(torch.cat((x, x1), 1))
|
143 |
+
if self.conv1x1:
|
144 |
+
x2 = x2 + self.conv1x1(x)
|
145 |
+
x3 = self.conv3(torch.cat((x, x1, x2), 1))
|
146 |
+
x4 = self.conv4(torch.cat((x, x1, x2, x3), 1))
|
147 |
+
if self.conv1x1:
|
148 |
+
x4 = x4 + x2
|
149 |
+
x5 = self.conv5(torch.cat((x, x1, x2, x3, x4), 1))
|
150 |
+
if self.noise:
|
151 |
+
return self.noise(x5.mul(0.2) + x)
|
152 |
+
else:
|
153 |
+
return x5 * 0.2 + x
|
154 |
+
|
155 |
+
|
156 |
+
####################
|
157 |
+
# ESRGANplus
|
158 |
+
####################
|
159 |
+
|
160 |
+
class GaussianNoise(nn.Module):
|
161 |
+
def __init__(self, sigma=0.1, is_relative_detach=False):
|
162 |
+
super().__init__()
|
163 |
+
self.sigma = sigma
|
164 |
+
self.is_relative_detach = is_relative_detach
|
165 |
+
self.noise = torch.tensor(0, dtype=torch.float)
|
166 |
+
|
167 |
+
def forward(self, x):
|
168 |
+
if self.training and self.sigma != 0:
|
169 |
+
self.noise = self.noise.to(x.device)
|
170 |
+
scale = self.sigma * x.detach() if self.is_relative_detach else self.sigma * x
|
171 |
+
sampled_noise = self.noise.repeat(*x.size()).normal_() * scale
|
172 |
+
x = x + sampled_noise
|
173 |
+
return x
|
174 |
+
|
175 |
+
def conv1x1(in_planes, out_planes, stride=1):
|
176 |
+
return nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=stride, bias=False)
|
177 |
+
|
178 |
+
|
179 |
+
####################
|
180 |
+
# SRVGGNetCompact
|
181 |
+
####################
|
182 |
+
|
183 |
+
class SRVGGNetCompact(nn.Module):
|
184 |
+
"""A compact VGG-style network structure for super-resolution.
|
185 |
+
This class is copied from https://github.com/xinntao/Real-ESRGAN
|
186 |
+
"""
|
187 |
+
|
188 |
+
def __init__(self, num_in_ch=3, num_out_ch=3, num_feat=64, num_conv=16, upscale=4, act_type='prelu'):
|
189 |
+
super(SRVGGNetCompact, self).__init__()
|
190 |
+
self.num_in_ch = num_in_ch
|
191 |
+
self.num_out_ch = num_out_ch
|
192 |
+
self.num_feat = num_feat
|
193 |
+
self.num_conv = num_conv
|
194 |
+
self.upscale = upscale
|
195 |
+
self.act_type = act_type
|
196 |
+
|
197 |
+
self.body = nn.ModuleList()
|
198 |
+
# the first conv
|
199 |
+
self.body.append(nn.Conv2d(num_in_ch, num_feat, 3, 1, 1))
|
200 |
+
# the first activation
|
201 |
+
if act_type == 'relu':
|
202 |
+
activation = nn.ReLU(inplace=True)
|
203 |
+
elif act_type == 'prelu':
|
204 |
+
activation = nn.PReLU(num_parameters=num_feat)
|
205 |
+
elif act_type == 'leakyrelu':
|
206 |
+
activation = nn.LeakyReLU(negative_slope=0.1, inplace=True)
|
207 |
+
self.body.append(activation)
|
208 |
+
|
209 |
+
# the body structure
|
210 |
+
for _ in range(num_conv):
|
211 |
+
self.body.append(nn.Conv2d(num_feat, num_feat, 3, 1, 1))
|
212 |
+
# activation
|
213 |
+
if act_type == 'relu':
|
214 |
+
activation = nn.ReLU(inplace=True)
|
215 |
+
elif act_type == 'prelu':
|
216 |
+
activation = nn.PReLU(num_parameters=num_feat)
|
217 |
+
elif act_type == 'leakyrelu':
|
218 |
+
activation = nn.LeakyReLU(negative_slope=0.1, inplace=True)
|
219 |
+
self.body.append(activation)
|
220 |
+
|
221 |
+
# the last conv
|
222 |
+
self.body.append(nn.Conv2d(num_feat, num_out_ch * upscale * upscale, 3, 1, 1))
|
223 |
+
# upsample
|
224 |
+
self.upsampler = nn.PixelShuffle(upscale)
|
225 |
+
|
226 |
+
def forward(self, x):
|
227 |
+
out = x
|
228 |
+
for i in range(0, len(self.body)):
|
229 |
+
out = self.body[i](out)
|
230 |
+
|
231 |
+
out = self.upsampler(out)
|
232 |
+
# add the nearest upsampled image, so that the network learns the residual
|
233 |
+
base = F.interpolate(x, scale_factor=self.upscale, mode='nearest')
|
234 |
+
out += base
|
235 |
+
return out
|
236 |
+
|
237 |
+
|
238 |
+
####################
|
239 |
+
# Upsampler
|
240 |
+
####################
|
241 |
+
|
242 |
+
class Upsample(nn.Module):
|
243 |
+
r"""Upsamples a given multi-channel 1D (temporal), 2D (spatial) or 3D (volumetric) data.
|
244 |
+
The input data is assumed to be of the form
|
245 |
+
`minibatch x channels x [optional depth] x [optional height] x width`.
|
246 |
+
"""
|
247 |
+
|
248 |
+
def __init__(self, size=None, scale_factor=None, mode="nearest", align_corners=None):
|
249 |
+
super(Upsample, self).__init__()
|
250 |
+
if isinstance(scale_factor, tuple):
|
251 |
+
self.scale_factor = tuple(float(factor) for factor in scale_factor)
|
252 |
+
else:
|
253 |
+
self.scale_factor = float(scale_factor) if scale_factor else None
|
254 |
+
self.mode = mode
|
255 |
+
self.size = size
|
256 |
+
self.align_corners = align_corners
|
257 |
+
|
258 |
+
def forward(self, x):
|
259 |
+
return nn.functional.interpolate(x, size=self.size, scale_factor=self.scale_factor, mode=self.mode, align_corners=self.align_corners)
|
260 |
+
|
261 |
+
def extra_repr(self):
|
262 |
+
if self.scale_factor is not None:
|
263 |
+
info = 'scale_factor=' + str(self.scale_factor)
|
264 |
+
else:
|
265 |
+
info = 'size=' + str(self.size)
|
266 |
+
info += ', mode=' + self.mode
|
267 |
+
return info
|
268 |
+
|
269 |
+
|
270 |
+
def pixel_unshuffle(x, scale):
|
271 |
+
""" Pixel unshuffle.
|
272 |
+
Args:
|
273 |
+
x (Tensor): Input feature with shape (b, c, hh, hw).
|
274 |
+
scale (int): Downsample ratio.
|
275 |
+
Returns:
|
276 |
+
Tensor: the pixel unshuffled feature.
|
277 |
+
"""
|
278 |
+
b, c, hh, hw = x.size()
|
279 |
+
out_channel = c * (scale**2)
|
280 |
+
assert hh % scale == 0 and hw % scale == 0
|
281 |
+
h = hh // scale
|
282 |
+
w = hw // scale
|
283 |
+
x_view = x.view(b, c, h, scale, w, scale)
|
284 |
+
return x_view.permute(0, 1, 3, 5, 2, 4).reshape(b, out_channel, h, w)
|
285 |
+
|
286 |
+
|
287 |
+
def pixelshuffle_block(in_nc, out_nc, upscale_factor=2, kernel_size=3, stride=1, bias=True,
|
288 |
+
pad_type='zero', norm_type=None, act_type='relu', convtype='Conv2D'):
|
289 |
+
"""
|
290 |
+
Pixel shuffle layer
|
291 |
+
(Real-Time Single Image and Video Super-Resolution Using an Efficient Sub-Pixel Convolutional
|
292 |
+
Neural Network, CVPR17)
|
293 |
+
"""
|
294 |
+
conv = conv_block(in_nc, out_nc * (upscale_factor ** 2), kernel_size, stride, bias=bias,
|
295 |
+
pad_type=pad_type, norm_type=None, act_type=None, convtype=convtype)
|
296 |
+
pixel_shuffle = nn.PixelShuffle(upscale_factor)
|
297 |
+
|
298 |
+
n = norm(norm_type, out_nc) if norm_type else None
|
299 |
+
a = act(act_type) if act_type else None
|
300 |
+
return sequential(conv, pixel_shuffle, n, a)
|
301 |
+
|
302 |
+
|
303 |
+
def upconv_block(in_nc, out_nc, upscale_factor=2, kernel_size=3, stride=1, bias=True,
|
304 |
+
pad_type='zero', norm_type=None, act_type='relu', mode='nearest', convtype='Conv2D'):
|
305 |
+
""" Upconv layer """
|
306 |
+
upscale_factor = (1, upscale_factor, upscale_factor) if convtype == 'Conv3D' else upscale_factor
|
307 |
+
upsample = Upsample(scale_factor=upscale_factor, mode=mode)
|
308 |
+
conv = conv_block(in_nc, out_nc, kernel_size, stride, bias=bias,
|
309 |
+
pad_type=pad_type, norm_type=norm_type, act_type=act_type, convtype=convtype)
|
310 |
+
return sequential(upsample, conv)
|
311 |
+
|
312 |
+
|
313 |
+
|
314 |
+
|
315 |
+
|
316 |
+
|
317 |
+
|
318 |
+
|
319 |
+
####################
|
320 |
+
# Basic blocks
|
321 |
+
####################
|
322 |
+
|
323 |
+
|
324 |
+
def make_layer(basic_block, num_basic_block, **kwarg):
|
325 |
+
"""Make layers by stacking the same blocks.
|
326 |
+
Args:
|
327 |
+
basic_block (nn.module): nn.module class for basic block. (block)
|
328 |
+
num_basic_block (int): number of blocks. (n_layers)
|
329 |
+
Returns:
|
330 |
+
nn.Sequential: Stacked blocks in nn.Sequential.
|
331 |
+
"""
|
332 |
+
layers = []
|
333 |
+
for _ in range(num_basic_block):
|
334 |
+
layers.append(basic_block(**kwarg))
|
335 |
+
return nn.Sequential(*layers)
|
336 |
+
|
337 |
+
|
338 |
+
def act(act_type, inplace=True, neg_slope=0.2, n_prelu=1, beta=1.0):
|
339 |
+
""" activation helper """
|
340 |
+
act_type = act_type.lower()
|
341 |
+
if act_type == 'relu':
|
342 |
+
layer = nn.ReLU(inplace)
|
343 |
+
elif act_type in ('leakyrelu', 'lrelu'):
|
344 |
+
layer = nn.LeakyReLU(neg_slope, inplace)
|
345 |
+
elif act_type == 'prelu':
|
346 |
+
layer = nn.PReLU(num_parameters=n_prelu, init=neg_slope)
|
347 |
+
elif act_type == 'tanh': # [-1, 1] range output
|
348 |
+
layer = nn.Tanh()
|
349 |
+
elif act_type == 'sigmoid': # [0, 1] range output
|
350 |
+
layer = nn.Sigmoid()
|
351 |
+
else:
|
352 |
+
raise NotImplementedError('activation layer [{:s}] is not found'.format(act_type))
|
353 |
+
return layer
|
354 |
+
|
355 |
+
|
356 |
+
class Identity(nn.Module):
|
357 |
+
def __init__(self, *kwargs):
|
358 |
+
super(Identity, self).__init__()
|
359 |
+
|
360 |
+
def forward(self, x, *kwargs):
|
361 |
+
return x
|
362 |
+
|
363 |
+
|
364 |
+
def norm(norm_type, nc):
|
365 |
+
""" Return a normalization layer """
|
366 |
+
norm_type = norm_type.lower()
|
367 |
+
if norm_type == 'batch':
|
368 |
+
layer = nn.BatchNorm2d(nc, affine=True)
|
369 |
+
elif norm_type == 'instance':
|
370 |
+
layer = nn.InstanceNorm2d(nc, affine=False)
|
371 |
+
elif norm_type == 'none':
|
372 |
+
def norm_layer(x): return Identity()
|
373 |
+
else:
|
374 |
+
raise NotImplementedError('normalization layer [{:s}] is not found'.format(norm_type))
|
375 |
+
return layer
|
376 |
+
|
377 |
+
|
378 |
+
def pad(pad_type, padding):
|
379 |
+
""" padding layer helper """
|
380 |
+
pad_type = pad_type.lower()
|
381 |
+
if padding == 0:
|
382 |
+
return None
|
383 |
+
if pad_type == 'reflect':
|
384 |
+
layer = nn.ReflectionPad2d(padding)
|
385 |
+
elif pad_type == 'replicate':
|
386 |
+
layer = nn.ReplicationPad2d(padding)
|
387 |
+
elif pad_type == 'zero':
|
388 |
+
layer = nn.ZeroPad2d(padding)
|
389 |
+
else:
|
390 |
+
raise NotImplementedError('padding layer [{:s}] is not implemented'.format(pad_type))
|
391 |
+
return layer
|
392 |
+
|
393 |
+
|
394 |
+
def get_valid_padding(kernel_size, dilation):
|
395 |
+
kernel_size = kernel_size + (kernel_size - 1) * (dilation - 1)
|
396 |
+
padding = (kernel_size - 1) // 2
|
397 |
+
return padding
|
398 |
+
|
399 |
+
|
400 |
+
class ShortcutBlock(nn.Module):
|
401 |
+
""" Elementwise sum the output of a submodule to its input """
|
402 |
+
def __init__(self, submodule):
|
403 |
+
super(ShortcutBlock, self).__init__()
|
404 |
+
self.sub = submodule
|
405 |
+
|
406 |
+
def forward(self, x):
|
407 |
+
output = x + self.sub(x)
|
408 |
+
return output
|
409 |
+
|
410 |
+
def __repr__(self):
|
411 |
+
return 'Identity + \n|' + self.sub.__repr__().replace('\n', '\n|')
|
412 |
+
|
413 |
+
|
414 |
+
def sequential(*args):
|
415 |
+
""" Flatten Sequential. It unwraps nn.Sequential. """
|
416 |
+
if len(args) == 1:
|
417 |
+
if isinstance(args[0], OrderedDict):
|
418 |
+
raise NotImplementedError('sequential does not support OrderedDict input.')
|
419 |
+
return args[0] # No sequential is needed.
|
420 |
+
modules = []
|
421 |
+
for module in args:
|
422 |
+
if isinstance(module, nn.Sequential):
|
423 |
+
for submodule in module.children():
|
424 |
+
modules.append(submodule)
|
425 |
+
elif isinstance(module, nn.Module):
|
426 |
+
modules.append(module)
|
427 |
+
return nn.Sequential(*modules)
|
428 |
+
|
429 |
+
|
430 |
+
def conv_block(in_nc, out_nc, kernel_size, stride=1, dilation=1, groups=1, bias=True,
|
431 |
+
pad_type='zero', norm_type=None, act_type='relu', mode='CNA', convtype='Conv2D',
|
432 |
+
spectral_norm=False):
|
433 |
+
""" Conv layer with padding, normalization, activation """
|
434 |
+
assert mode in ['CNA', 'NAC', 'CNAC'], 'Wrong conv mode [{:s}]'.format(mode)
|
435 |
+
padding = get_valid_padding(kernel_size, dilation)
|
436 |
+
p = pad(pad_type, padding) if pad_type and pad_type != 'zero' else None
|
437 |
+
padding = padding if pad_type == 'zero' else 0
|
438 |
+
|
439 |
+
if convtype=='PartialConv2D':
|
440 |
+
c = PartialConv2d(in_nc, out_nc, kernel_size=kernel_size, stride=stride, padding=padding,
|
441 |
+
dilation=dilation, bias=bias, groups=groups)
|
442 |
+
elif convtype=='DeformConv2D':
|
443 |
+
c = DeformConv2d(in_nc, out_nc, kernel_size=kernel_size, stride=stride, padding=padding,
|
444 |
+
dilation=dilation, bias=bias, groups=groups)
|
445 |
+
elif convtype=='Conv3D':
|
446 |
+
c = nn.Conv3d(in_nc, out_nc, kernel_size=kernel_size, stride=stride, padding=padding,
|
447 |
+
dilation=dilation, bias=bias, groups=groups)
|
448 |
+
else:
|
449 |
+
c = nn.Conv2d(in_nc, out_nc, kernel_size=kernel_size, stride=stride, padding=padding,
|
450 |
+
dilation=dilation, bias=bias, groups=groups)
|
451 |
+
|
452 |
+
if spectral_norm:
|
453 |
+
c = nn.utils.spectral_norm(c)
|
454 |
+
|
455 |
+
a = act(act_type) if act_type else None
|
456 |
+
if 'CNA' in mode:
|
457 |
+
n = norm(norm_type, out_nc) if norm_type else None
|
458 |
+
return sequential(p, c, n, a)
|
459 |
+
elif mode == 'NAC':
|
460 |
+
if norm_type is None and act_type is not None:
|
461 |
+
a = act(act_type, inplace=False)
|
462 |
+
n = norm(norm_type, in_nc) if norm_type else None
|
463 |
+
return sequential(n, a, p, c)
|
stable-diffusion-webui-master/modules/extensions.py
ADDED
@@ -0,0 +1,89 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import sys
|
3 |
+
import traceback
|
4 |
+
|
5 |
+
import git
|
6 |
+
|
7 |
+
from modules import paths, shared
|
8 |
+
|
9 |
+
extensions = []
|
10 |
+
extensions_dir = os.path.join(paths.script_path, "extensions")
|
11 |
+
|
12 |
+
|
13 |
+
def active():
|
14 |
+
return [x for x in extensions if x.enabled]
|
15 |
+
|
16 |
+
|
17 |
+
class Extension:
|
18 |
+
def __init__(self, name, path, enabled=True):
|
19 |
+
self.name = name
|
20 |
+
self.path = path
|
21 |
+
self.enabled = enabled
|
22 |
+
self.status = ''
|
23 |
+
self.can_update = False
|
24 |
+
|
25 |
+
repo = None
|
26 |
+
try:
|
27 |
+
if os.path.exists(os.path.join(path, ".git")):
|
28 |
+
repo = git.Repo(path)
|
29 |
+
except Exception:
|
30 |
+
print(f"Error reading github repository info from {path}:", file=sys.stderr)
|
31 |
+
print(traceback.format_exc(), file=sys.stderr)
|
32 |
+
|
33 |
+
if repo is None or repo.bare:
|
34 |
+
self.remote = None
|
35 |
+
else:
|
36 |
+
try:
|
37 |
+
self.remote = next(repo.remote().urls, None)
|
38 |
+
self.status = 'unknown'
|
39 |
+
except Exception:
|
40 |
+
self.remote = None
|
41 |
+
|
42 |
+
def list_files(self, subdir, extension):
|
43 |
+
from modules import scripts
|
44 |
+
|
45 |
+
dirpath = os.path.join(self.path, subdir)
|
46 |
+
if not os.path.isdir(dirpath):
|
47 |
+
return []
|
48 |
+
|
49 |
+
res = []
|
50 |
+
for filename in sorted(os.listdir(dirpath)):
|
51 |
+
res.append(scripts.ScriptFile(self.path, filename, os.path.join(dirpath, filename)))
|
52 |
+
|
53 |
+
res = [x for x in res if os.path.splitext(x.path)[1].lower() == extension and os.path.isfile(x.path)]
|
54 |
+
|
55 |
+
return res
|
56 |
+
|
57 |
+
def check_updates(self):
|
58 |
+
repo = git.Repo(self.path)
|
59 |
+
for fetch in repo.remote().fetch("--dry-run"):
|
60 |
+
if fetch.flags != fetch.HEAD_UPTODATE:
|
61 |
+
self.can_update = True
|
62 |
+
self.status = "behind"
|
63 |
+
return
|
64 |
+
|
65 |
+
self.can_update = False
|
66 |
+
self.status = "latest"
|
67 |
+
|
68 |
+
def fetch_and_reset_hard(self):
|
69 |
+
repo = git.Repo(self.path)
|
70 |
+
# Fix: `error: Your local changes to the following files would be overwritten by merge`,
|
71 |
+
# because WSL2 Docker set 755 file permissions instead of 644, this results to the error.
|
72 |
+
repo.git.fetch('--all')
|
73 |
+
repo.git.reset('--hard', 'origin')
|
74 |
+
|
75 |
+
|
76 |
+
def list_extensions():
|
77 |
+
extensions.clear()
|
78 |
+
|
79 |
+
if not os.path.isdir(extensions_dir):
|
80 |
+
return
|
81 |
+
|
82 |
+
for dirname in sorted(os.listdir(extensions_dir)):
|
83 |
+
path = os.path.join(extensions_dir, dirname)
|
84 |
+
if not os.path.isdir(path):
|
85 |
+
continue
|
86 |
+
|
87 |
+
extension = Extension(name=dirname, path=path, enabled=dirname not in shared.opts.disabled_extensions)
|
88 |
+
extensions.append(extension)
|
89 |
+
|
stable-diffusion-webui-master/modules/extras.py
ADDED
@@ -0,0 +1,313 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from __future__ import annotations
|
2 |
+
import math
|
3 |
+
import os
|
4 |
+
import sys
|
5 |
+
import traceback
|
6 |
+
|
7 |
+
import numpy as np
|
8 |
+
from PIL import Image
|
9 |
+
|
10 |
+
import torch
|
11 |
+
import tqdm
|
12 |
+
|
13 |
+
from typing import Callable, List, OrderedDict, Tuple
|
14 |
+
from functools import partial
|
15 |
+
from dataclasses import dataclass
|
16 |
+
|
17 |
+
from modules import processing, shared, images, devices, sd_models, sd_samplers
|
18 |
+
from modules.shared import opts
|
19 |
+
import modules.gfpgan_model
|
20 |
+
from modules.ui import plaintext_to_html
|
21 |
+
import modules.codeformer_model
|
22 |
+
import piexif
|
23 |
+
import piexif.helper
|
24 |
+
import gradio as gr
|
25 |
+
import safetensors.torch
|
26 |
+
|
27 |
+
class LruCache(OrderedDict):
|
28 |
+
@dataclass(frozen=True)
|
29 |
+
class Key:
|
30 |
+
image_hash: int
|
31 |
+
info_hash: int
|
32 |
+
args_hash: int
|
33 |
+
|
34 |
+
@dataclass
|
35 |
+
class Value:
|
36 |
+
image: Image.Image
|
37 |
+
info: str
|
38 |
+
|
39 |
+
def __init__(self, max_size: int = 5, *args, **kwargs):
|
40 |
+
super().__init__(*args, **kwargs)
|
41 |
+
self._max_size = max_size
|
42 |
+
|
43 |
+
def get(self, key: LruCache.Key) -> LruCache.Value:
|
44 |
+
ret = super().get(key)
|
45 |
+
if ret is not None:
|
46 |
+
self.move_to_end(key) # Move to end of eviction list
|
47 |
+
return ret
|
48 |
+
|
49 |
+
def put(self, key: LruCache.Key, value: LruCache.Value) -> None:
|
50 |
+
self[key] = value
|
51 |
+
while len(self) > self._max_size:
|
52 |
+
self.popitem(last=False)
|
53 |
+
|
54 |
+
|
55 |
+
cached_images: LruCache = LruCache(max_size=5)
|
56 |
+
|
57 |
+
|
58 |
+
def run_extras(extras_mode, resize_mode, image, image_folder, input_dir, output_dir, show_extras_results, gfpgan_visibility, codeformer_visibility, codeformer_weight, upscaling_resize, upscaling_resize_w, upscaling_resize_h, upscaling_crop, extras_upscaler_1, extras_upscaler_2, extras_upscaler_2_visibility, upscale_first: bool):
|
59 |
+
devices.torch_gc()
|
60 |
+
|
61 |
+
imageArr = []
|
62 |
+
# Also keep track of original file names
|
63 |
+
imageNameArr = []
|
64 |
+
outputs = []
|
65 |
+
|
66 |
+
if extras_mode == 1:
|
67 |
+
#convert file to pillow image
|
68 |
+
for img in image_folder:
|
69 |
+
image = Image.open(img)
|
70 |
+
imageArr.append(image)
|
71 |
+
imageNameArr.append(os.path.splitext(img.orig_name)[0])
|
72 |
+
elif extras_mode == 2:
|
73 |
+
assert not shared.cmd_opts.hide_ui_dir_config, '--hide-ui-dir-config option must be disabled'
|
74 |
+
|
75 |
+
if input_dir == '':
|
76 |
+
return outputs, "Please select an input directory.", ''
|
77 |
+
image_list = shared.listfiles(input_dir)
|
78 |
+
for img in image_list:
|
79 |
+
try:
|
80 |
+
image = Image.open(img)
|
81 |
+
except Exception:
|
82 |
+
continue
|
83 |
+
imageArr.append(image)
|
84 |
+
imageNameArr.append(img)
|
85 |
+
else:
|
86 |
+
imageArr.append(image)
|
87 |
+
imageNameArr.append(None)
|
88 |
+
|
89 |
+
if extras_mode == 2 and output_dir != '':
|
90 |
+
outpath = output_dir
|
91 |
+
else:
|
92 |
+
outpath = opts.outdir_samples or opts.outdir_extras_samples
|
93 |
+
|
94 |
+
# Extra operation definitions
|
95 |
+
|
96 |
+
def run_gfpgan(image: Image.Image, info: str) -> Tuple[Image.Image, str]:
|
97 |
+
restored_img = modules.gfpgan_model.gfpgan_fix_faces(np.array(image, dtype=np.uint8))
|
98 |
+
res = Image.fromarray(restored_img)
|
99 |
+
|
100 |
+
if gfpgan_visibility < 1.0:
|
101 |
+
res = Image.blend(image, res, gfpgan_visibility)
|
102 |
+
|
103 |
+
info += f"GFPGAN visibility:{round(gfpgan_visibility, 2)}\n"
|
104 |
+
return (res, info)
|
105 |
+
|
106 |
+
def run_codeformer(image: Image.Image, info: str) -> Tuple[Image.Image, str]:
|
107 |
+
restored_img = modules.codeformer_model.codeformer.restore(np.array(image, dtype=np.uint8), w=codeformer_weight)
|
108 |
+
res = Image.fromarray(restored_img)
|
109 |
+
|
110 |
+
if codeformer_visibility < 1.0:
|
111 |
+
res = Image.blend(image, res, codeformer_visibility)
|
112 |
+
|
113 |
+
info += f"CodeFormer w: {round(codeformer_weight, 2)}, CodeFormer visibility:{round(codeformer_visibility, 2)}\n"
|
114 |
+
return (res, info)
|
115 |
+
|
116 |
+
def upscale(image, scaler_index, resize, mode, resize_w, resize_h, crop):
|
117 |
+
upscaler = shared.sd_upscalers[scaler_index]
|
118 |
+
res = upscaler.scaler.upscale(image, resize, upscaler.data_path)
|
119 |
+
if mode == 1 and crop:
|
120 |
+
cropped = Image.new("RGB", (resize_w, resize_h))
|
121 |
+
cropped.paste(res, box=(resize_w // 2 - res.width // 2, resize_h // 2 - res.height // 2))
|
122 |
+
res = cropped
|
123 |
+
return res
|
124 |
+
|
125 |
+
def run_prepare_crop(image: Image.Image, info: str) -> Tuple[Image.Image, str]:
|
126 |
+
# Actual crop happens in run_upscalers_blend, this just sets upscaling_resize and adds info text
|
127 |
+
nonlocal upscaling_resize
|
128 |
+
if resize_mode == 1:
|
129 |
+
upscaling_resize = max(upscaling_resize_w/image.width, upscaling_resize_h/image.height)
|
130 |
+
crop_info = " (crop)" if upscaling_crop else ""
|
131 |
+
info += f"Resize to: {upscaling_resize_w:g}x{upscaling_resize_h:g}{crop_info}\n"
|
132 |
+
return (image, info)
|
133 |
+
|
134 |
+
@dataclass
|
135 |
+
class UpscaleParams:
|
136 |
+
upscaler_idx: int
|
137 |
+
blend_alpha: float
|
138 |
+
|
139 |
+
def run_upscalers_blend(params: List[UpscaleParams], image: Image.Image, info: str) -> Tuple[Image.Image, str]:
|
140 |
+
blended_result: Image.Image = None
|
141 |
+
image_hash: str = hash(np.array(image.getdata()).tobytes())
|
142 |
+
for upscaler in params:
|
143 |
+
upscale_args = (upscaler.upscaler_idx, upscaling_resize, resize_mode,
|
144 |
+
upscaling_resize_w, upscaling_resize_h, upscaling_crop)
|
145 |
+
cache_key = LruCache.Key(image_hash=image_hash,
|
146 |
+
info_hash=hash(info),
|
147 |
+
args_hash=hash(upscale_args))
|
148 |
+
cached_entry = cached_images.get(cache_key)
|
149 |
+
if cached_entry is None:
|
150 |
+
res = upscale(image, *upscale_args)
|
151 |
+
info += f"Upscale: {round(upscaling_resize, 3)}, visibility: {upscaler.blend_alpha}, model:{shared.sd_upscalers[upscaler.upscaler_idx].name}\n"
|
152 |
+
cached_images.put(cache_key, LruCache.Value(image=res, info=info))
|
153 |
+
else:
|
154 |
+
res, info = cached_entry.image, cached_entry.info
|
155 |
+
|
156 |
+
if blended_result is None:
|
157 |
+
blended_result = res
|
158 |
+
else:
|
159 |
+
blended_result = Image.blend(blended_result, res, upscaler.blend_alpha)
|
160 |
+
return (blended_result, info)
|
161 |
+
|
162 |
+
# Build a list of operations to run
|
163 |
+
facefix_ops: List[Callable] = []
|
164 |
+
facefix_ops += [run_gfpgan] if gfpgan_visibility > 0 else []
|
165 |
+
facefix_ops += [run_codeformer] if codeformer_visibility > 0 else []
|
166 |
+
|
167 |
+
upscale_ops: List[Callable] = []
|
168 |
+
upscale_ops += [run_prepare_crop] if resize_mode == 1 else []
|
169 |
+
|
170 |
+
if upscaling_resize != 0:
|
171 |
+
step_params: List[UpscaleParams] = []
|
172 |
+
step_params.append(UpscaleParams(upscaler_idx=extras_upscaler_1, blend_alpha=1.0))
|
173 |
+
if extras_upscaler_2 != 0 and extras_upscaler_2_visibility > 0:
|
174 |
+
step_params.append(UpscaleParams(upscaler_idx=extras_upscaler_2, blend_alpha=extras_upscaler_2_visibility))
|
175 |
+
|
176 |
+
upscale_ops.append(partial(run_upscalers_blend, step_params))
|
177 |
+
|
178 |
+
extras_ops: List[Callable] = (upscale_ops + facefix_ops) if upscale_first else (facefix_ops + upscale_ops)
|
179 |
+
|
180 |
+
for image, image_name in zip(imageArr, imageNameArr):
|
181 |
+
if image is None:
|
182 |
+
return outputs, "Please select an input image.", ''
|
183 |
+
existing_pnginfo = image.info or {}
|
184 |
+
|
185 |
+
image = image.convert("RGB")
|
186 |
+
info = ""
|
187 |
+
# Run each operation on each image
|
188 |
+
for op in extras_ops:
|
189 |
+
image, info = op(image, info)
|
190 |
+
|
191 |
+
if opts.use_original_name_batch and image_name != None:
|
192 |
+
basename = os.path.splitext(os.path.basename(image_name))[0]
|
193 |
+
else:
|
194 |
+
basename = ''
|
195 |
+
|
196 |
+
images.save_image(image, path=outpath, basename=basename, seed=None, prompt=None, extension=opts.samples_format, info=info, short_filename=True,
|
197 |
+
no_prompt=True, grid=False, pnginfo_section_name="extras", existing_info=existing_pnginfo, forced_filename=None)
|
198 |
+
|
199 |
+
if opts.enable_pnginfo:
|
200 |
+
image.info = existing_pnginfo
|
201 |
+
image.info["extras"] = info
|
202 |
+
|
203 |
+
if extras_mode != 2 or show_extras_results :
|
204 |
+
outputs.append(image)
|
205 |
+
|
206 |
+
devices.torch_gc()
|
207 |
+
|
208 |
+
return outputs, plaintext_to_html(info), ''
|
209 |
+
|
210 |
+
def clear_cache():
|
211 |
+
cached_images.clear()
|
212 |
+
|
213 |
+
|
214 |
+
def run_pnginfo(image):
|
215 |
+
if image is None:
|
216 |
+
return '', '', ''
|
217 |
+
|
218 |
+
geninfo, items = images.read_info_from_image(image)
|
219 |
+
items = {**{'parameters': geninfo}, **items}
|
220 |
+
|
221 |
+
info = ''
|
222 |
+
for key, text in items.items():
|
223 |
+
info += f"""
|
224 |
+
<div>
|
225 |
+
<p><b>{plaintext_to_html(str(key))}</b></p>
|
226 |
+
<p>{plaintext_to_html(str(text))}</p>
|
227 |
+
</div>
|
228 |
+
""".strip()+"\n"
|
229 |
+
|
230 |
+
if len(info) == 0:
|
231 |
+
message = "Nothing found in the image."
|
232 |
+
info = f"<div><p>{message}<p></div>"
|
233 |
+
|
234 |
+
return '', geninfo, info
|
235 |
+
|
236 |
+
|
237 |
+
def run_modelmerger(primary_model_name, secondary_model_name, teritary_model_name, interp_method, multiplier, save_as_half, custom_name, checkpoint_format):
|
238 |
+
def weighted_sum(theta0, theta1, alpha):
|
239 |
+
return ((1 - alpha) * theta0) + (alpha * theta1)
|
240 |
+
|
241 |
+
def get_difference(theta1, theta2):
|
242 |
+
return theta1 - theta2
|
243 |
+
|
244 |
+
def add_difference(theta0, theta1_2_diff, alpha):
|
245 |
+
return theta0 + (alpha * theta1_2_diff)
|
246 |
+
|
247 |
+
primary_model_info = sd_models.checkpoints_list[primary_model_name]
|
248 |
+
secondary_model_info = sd_models.checkpoints_list[secondary_model_name]
|
249 |
+
teritary_model_info = sd_models.checkpoints_list.get(teritary_model_name, None)
|
250 |
+
|
251 |
+
print(f"Loading {primary_model_info.filename}...")
|
252 |
+
theta_0 = sd_models.read_state_dict(primary_model_info.filename, map_location='cpu')
|
253 |
+
|
254 |
+
print(f"Loading {secondary_model_info.filename}...")
|
255 |
+
theta_1 = sd_models.read_state_dict(secondary_model_info.filename, map_location='cpu')
|
256 |
+
|
257 |
+
if teritary_model_info is not None:
|
258 |
+
print(f"Loading {teritary_model_info.filename}...")
|
259 |
+
theta_2 = sd_models.read_state_dict(teritary_model_info.filename, map_location='cpu')
|
260 |
+
else:
|
261 |
+
theta_2 = None
|
262 |
+
|
263 |
+
theta_funcs = {
|
264 |
+
"Weighted sum": (None, weighted_sum),
|
265 |
+
"Add difference": (get_difference, add_difference),
|
266 |
+
}
|
267 |
+
theta_func1, theta_func2 = theta_funcs[interp_method]
|
268 |
+
|
269 |
+
print(f"Merging...")
|
270 |
+
|
271 |
+
if theta_func1:
|
272 |
+
for key in tqdm.tqdm(theta_1.keys()):
|
273 |
+
if 'model' in key:
|
274 |
+
if key in theta_2:
|
275 |
+
t2 = theta_2.get(key, torch.zeros_like(theta_1[key]))
|
276 |
+
theta_1[key] = theta_func1(theta_1[key], t2)
|
277 |
+
else:
|
278 |
+
theta_1[key] = torch.zeros_like(theta_1[key])
|
279 |
+
del theta_2
|
280 |
+
|
281 |
+
for key in tqdm.tqdm(theta_0.keys()):
|
282 |
+
if 'model' in key and key in theta_1:
|
283 |
+
|
284 |
+
theta_0[key] = theta_func2(theta_0[key], theta_1[key], multiplier)
|
285 |
+
|
286 |
+
if save_as_half:
|
287 |
+
theta_0[key] = theta_0[key].half()
|
288 |
+
|
289 |
+
# I believe this part should be discarded, but I'll leave it for now until I am sure
|
290 |
+
for key in theta_1.keys():
|
291 |
+
if 'model' in key and key not in theta_0:
|
292 |
+
theta_0[key] = theta_1[key]
|
293 |
+
if save_as_half:
|
294 |
+
theta_0[key] = theta_0[key].half()
|
295 |
+
|
296 |
+
ckpt_dir = shared.cmd_opts.ckpt_dir or sd_models.model_path
|
297 |
+
|
298 |
+
filename = primary_model_info.model_name + '_' + str(round(1-multiplier, 2)) + '-' + secondary_model_info.model_name + '_' + str(round(multiplier, 2)) + '-' + interp_method.replace(" ", "_") + '-merged.' + checkpoint_format
|
299 |
+
filename = filename if custom_name == '' else (custom_name + '.' + checkpoint_format)
|
300 |
+
output_modelname = os.path.join(ckpt_dir, filename)
|
301 |
+
|
302 |
+
print(f"Saving to {output_modelname}...")
|
303 |
+
|
304 |
+
_, extension = os.path.splitext(output_modelname)
|
305 |
+
if extension.lower() == ".safetensors":
|
306 |
+
safetensors.torch.save_file(theta_0, output_modelname, metadata={"format": "pt"})
|
307 |
+
else:
|
308 |
+
torch.save(theta_0, output_modelname)
|
309 |
+
|
310 |
+
sd_models.list_models()
|
311 |
+
|
312 |
+
print(f"Checkpoint saved.")
|
313 |
+
return ["Checkpoint saved to " + output_modelname] + [gr.Dropdown.update(choices=sd_models.checkpoint_tiles()) for _ in range(4)]
|
stable-diffusion-webui-master/modules/face_restoration.py
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from modules import shared
|
2 |
+
|
3 |
+
|
4 |
+
class FaceRestoration:
|
5 |
+
def name(self):
|
6 |
+
return "None"
|
7 |
+
|
8 |
+
def restore(self, np_image):
|
9 |
+
return np_image
|
10 |
+
|
11 |
+
|
12 |
+
def restore_faces(np_image):
|
13 |
+
face_restorers = [x for x in shared.face_restorers if x.name() == shared.opts.face_restoration_model or shared.opts.face_restoration_model is None]
|
14 |
+
if len(face_restorers) == 0:
|
15 |
+
return np_image
|
16 |
+
|
17 |
+
face_restorer = face_restorers[0]
|
18 |
+
|
19 |
+
return face_restorer.restore(np_image)
|