aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/ISSUE_TEMPLATE/bug_report.md32
-rw-r--r--.github/ISSUE_TEMPLATE/bug_report.yml83
-rw-r--r--.github/ISSUE_TEMPLATE/config.yml5
-rw-r--r--.github/ISSUE_TEMPLATE/feature_request.md20
-rw-r--r--.github/ISSUE_TEMPLATE/feature_request.yml40
-rw-r--r--.gitignore3
-rw-r--r--README.md49
-rw-r--r--extensions/put extensions here.txt0
-rw-r--r--javascript/aspectRatioOverlay.js55
-rw-r--r--javascript/dragdrop.js2
-rw-r--r--javascript/hints.js6
-rw-r--r--javascript/images_history.js206
-rw-r--r--javascript/localization.js21
-rw-r--r--launch.py12
-rw-r--r--localizations/ar_AR.json456
-rw-r--r--localizations/es_ES.json418
-rw-r--r--localizations/ja_JP.json482
-rw-r--r--localizations/ko_KR.json497
-rw-r--r--localizations/ru_RU.json475
-rw-r--r--modules/api/api.py66
-rw-r--r--modules/api/models.py (renamed from modules/api/processing.py)11
-rw-r--r--modules/bsrgan_model.py76
-rw-r--r--modules/bsrgan_model_arch.py102
-rw-r--r--modules/deepbooru.py5
-rw-r--r--modules/devices.py23
-rw-r--r--modules/esrgan_model.py192
-rw-r--r--modules/esrgan_model_arch.py487
-rw-r--r--modules/extras.py19
-rw-r--r--modules/generation_parameters_copypaste.py25
-rw-r--r--modules/hypernetworks/hypernetwork.py217
-rw-r--r--modules/hypernetworks/ui.py28
-rw-r--r--modules/images.py201
-rw-r--r--modules/images_history.py183
-rw-r--r--modules/img2img.py3
-rw-r--r--modules/interrogate.py12
-rw-r--r--modules/lowvram.py9
-rw-r--r--modules/processing.py146
-rw-r--r--modules/script_callbacks.py100
-rw-r--r--modules/scripts.py246
-rw-r--r--modules/scunet_model.py3
-rw-r--r--modules/sd_hijack.py29
-rw-r--r--modules/sd_hijack_inpainting.py331
-rw-r--r--modules/sd_models.py34
-rw-r--r--modules/sd_samplers.py81
-rw-r--r--modules/shared.py45
-rw-r--r--modules/swinir_model.py12
-rw-r--r--modules/textual_inversion/dataset.py4
-rw-r--r--modules/textual_inversion/image_embedding.py5
-rw-r--r--modules/textual_inversion/preprocess.py91
-rw-r--r--modules/textual_inversion/textual_inversion.py6
-rw-r--r--modules/textual_inversion/ui.py4
-rw-r--r--modules/txt2img.py7
-rw-r--r--modules/ui.py201
-rw-r--r--scripts/img2imgalt.py8
-rw-r--r--scripts/outpainting_mk_2.py139
-rw-r--r--scripts/xy_grid.py1
-rw-r--r--style.css74
-rw-r--r--webui.py23
58 files changed, 4855 insertions, 1256 deletions
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
deleted file mode 100644
index 50c54210..00000000
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ /dev/null
@@ -1,32 +0,0 @@
----
-name: Bug report
-about: Create a report to help us improve
-title: ''
-labels: bug-report
-assignees: ''
-
----
-
-**Describe the bug**
-A clear and concise description of what the bug is.
-
-**To Reproduce**
-Steps to reproduce the behavior:
-1. Go to '...'
-2. Click on '....'
-3. Scroll down to '....'
-4. See error
-
-**Expected behavior**
-A clear and concise description of what you expected to happen.
-
-**Screenshots**
-If applicable, add screenshots to help explain your problem.
-
-**Desktop (please complete the following information):**
- - OS: [e.g. Windows, Linux]
- - Browser [e.g. chrome, safari]
- - Commit revision [looks like this: e68484500f76a33ba477d5a99340ab30451e557b; can be seen when launching webui.bat, or obtained manually by running `git rev-parse HEAD`]
-
-**Additional context**
-Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
new file mode 100644
index 00000000..9c2ff313
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -0,0 +1,83 @@
+name: Bug Report
+description: You think somethings is broken in the UI
+title: "[Bug]: "
+labels: ["bug-report"]
+
+body:
+ - type: checkboxes
+ attributes:
+ label: Is there an existing issue for this?
+ 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.
+ options:
+ - label: I have searched the existing issues and checked the recent builds/commits
+ required: true
+ - type: markdown
+ attributes:
+ value: |
+ *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**
+ - type: textarea
+ id: what-did
+ attributes:
+ label: What happened?
+ description: Tell us what happened in a very clear and simple way
+ validations:
+ required: true
+ - type: textarea
+ id: steps
+ attributes:
+ label: Steps to reproduce the problem
+ description: Please provide us with precise step by step information on how to reproduce the bug
+ value: |
+ 1. Go to ....
+ 2. Press ....
+ 3. ...
+ validations:
+ required: true
+ - type: textarea
+ id: what-should
+ attributes:
+ label: What should have happened?
+ description: tell what you think the normal behavior should be
+ validations:
+ required: true
+ - type: input
+ id: commit
+ attributes:
+ label: Commit where the problem happens
+ description: Which commit are you running ? (copy the **Commit hash** shown in the cmd/terminal when you launch the UI)
+ validations:
+ required: true
+ - type: dropdown
+ id: platforms
+ attributes:
+ label: What platforms do you use to access UI ?
+ multiple: true
+ options:
+ - Windows
+ - Linux
+ - MacOS
+ - iOS
+ - Android
+ - Other/Cloud
+ - type: dropdown
+ id: browsers
+ attributes:
+ label: What browsers do you use to access the UI ?
+ multiple: true
+ options:
+ - Mozilla Firefox
+ - Google Chrome
+ - Brave
+ - Apple Safari
+ - Microsoft Edge
+ - type: textarea
+ id: cmdargs
+ attributes:
+ label: Command Line Arguments
+ description: Are you using any launching parameters/command line arguments (modified webui-user.py) ? If yes, please write them below
+ render: Shell
+ - type: textarea
+ id: misc
+ attributes:
+ label: Additional information, context and logs
+ description: Please provide us with any relevant additional info, context or log output.
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 00000000..f58c94a9
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,5 @@
+blank_issues_enabled: false
+contact_links:
+ - name: WebUI Community Support
+ url: https://github.com/AUTOMATIC1111/stable-diffusion-webui/discussions
+ about: Please ask and answer questions here.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
deleted file mode 100644
index eda42fa7..00000000
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-name: Feature request
-about: Suggest an idea for this project
-title: ''
-labels: 'suggestion'
-assignees: ''
-
----
-
-**Is your feature request related to a problem? Please describe.**
-A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
-
-**Describe the solution you'd like**
-A clear and concise description of what you want to happen.
-
-**Describe alternatives you've considered**
-A clear and concise description of any alternative solutions or features you've considered.
-
-**Additional context**
-Add any other context or screenshots about the feature request here.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
new file mode 100644
index 00000000..8ca6e21f
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -0,0 +1,40 @@
+name: Feature request
+description: Suggest an idea for this project
+title: "[Feature Request]: "
+labels: ["suggestion"]
+
+body:
+ - type: checkboxes
+ attributes:
+ label: Is there an existing issue for this?
+ 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.
+ options:
+ - label: I have searched the existing issues and checked the recent builds/commits
+ required: true
+ - type: markdown
+ attributes:
+ value: |
+ *Please fill this form with as much information as possible, provide screenshots and/or illustrations of the feature if possible*
+ - type: textarea
+ id: feature
+ attributes:
+ label: What would your feature do ?
+ description: Tell us about your feature in a very clear and simple way, and what problem it would solve
+ validations:
+ required: true
+ - type: textarea
+ id: workflow
+ attributes:
+ label: Proposed workflow
+ description: Please provide us with step by step information on how you'd like the feature to be accessed and used
+ value: |
+ 1. Go to ....
+ 2. Press ....
+ 3. ...
+ validations:
+ required: true
+ - type: textarea
+ id: misc
+ attributes:
+ label: Additional information
+ description: Add any other context or screenshots about the feature request here.
diff --git a/.gitignore b/.gitignore
index 69785b3e..70660c51 100644
--- a/.gitignore
+++ b/.gitignore
@@ -27,3 +27,6 @@ __pycache__
notification.mp3
/SwinIR
/textual_inversion
+.vscode
+/extensions
+
diff --git a/README.md b/README.md
index 859a91b6..55c050d5 100644
--- a/README.md
+++ b/README.md
@@ -11,6 +11,7 @@ Check the [custom scripts](https://github.com/AUTOMATIC1111/stable-diffusion-web
- One click install and run script (but you still must install python and git)
- Outpainting
- Inpainting
+- Color Sketch
- Prompt Matrix
- Stable Diffusion Upscale
- Attention, specify parts of text that the model should pay more attention to
@@ -23,6 +24,7 @@ Check the [custom scripts](https://github.com/AUTOMATIC1111/stable-diffusion-web
- have as many embeddings as you want and use any names you like for them
- use multiple embeddings with different numbers of vectors per token
- works with half precision floating point numbers
+ - train embeddings on 8GB (also reports of 6GB working)
- Extras tab with:
- GFPGAN, neural network that fixes faces
- CodeFormer, face restoration tool as an alternative to GFPGAN
@@ -37,14 +39,14 @@ Check the [custom scripts](https://github.com/AUTOMATIC1111/stable-diffusion-web
- Interrupt processing at any time
- 4GB video card support (also reports of 2GB working)
- Correct seeds for batches
-- Prompt length validation
- - get length of prompt in tokens as you type
- - get a warning after generation if some text was truncated
+- Live prompt token length validation
- Generation parameters
- parameters you used to generate images are saved with that image
- in PNG chunks for PNG, in EXIF for JPEG
- can drag the image to PNG info tab to restore generation parameters and automatically copy them into UI
- can be disabled in settings
+ - drag and drop an image/text-parameters to promptbox
+- Read Generation Parameters Button, loads parameters in promptbox to UI
- Settings page
- Running arbitrary python code from UI (must run with --allow-code to enable)
- Mouseover hints for most UI elements
@@ -59,10 +61,10 @@ Check the [custom scripts](https://github.com/AUTOMATIC1111/stable-diffusion-web
- CLIP interrogator, a button that tries to guess prompt from an image
- Prompt Editing, a way to change prompt mid-generation, say to start making a watermelon and switch to anime girl midway
- Batch Processing, process a group of files using img2img
-- Img2img Alternative
+- Img2img Alternative, reverse Euler method of cross attention control
- Highres Fix, a convenience option to produce high resolution pictures in one click without usual distortions
- Reloading checkpoints on the fly
-- Checkpoint Merger, a tab that allows you to merge two checkpoints into one
+- Checkpoint Merger, a tab that allows you to merge up to 3 checkpoints into one
- [Custom scripts](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Custom-Scripts) with many extensions from community
- [Composable-Diffusion](https://energy-based-model.github.io/Compositional-Visual-Generation-with-Composable-Diffusion-Models/), a way to use multiple prompts at once
- separate prompts using uppercase `AND`
@@ -70,14 +72,45 @@ Check the [custom scripts](https://github.com/AUTOMATIC1111/stable-diffusion-web
- No token limit for prompts (original stable diffusion lets you use up to 75 tokens)
- DeepDanbooru integration, creates danbooru style tags for anime prompts (add --deepdanbooru to commandline args)
- [xformers](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Xformers), major speed increase for select cards: (add --xformers to commandline args)
+- via extension: [History tab](https://github.com/yfszzx/stable-diffusion-webui-images-browser): view, direct and delete images conveniently within the UI
+- Generate forever option
+- Training tab
+ - hypernetworks and embeddings options
+ - Preprocessing images: cropping, mirroring, autotagging using BLIP or deepdanbooru (for anime)
+- Clip skip
+- Use Hypernetworks
+- Use VAEs
+- Estimated completion time in progress bar
+- API
+- Support for dedicated [inpainting model](https://github.com/runwayml/stable-diffusion#inpainting-with-stable-diffusion) by RunwayML.
+- 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))
+
+## Where are Aesthetic Gradients?!?!
+Aesthetic Gradients are now an extension. You can install it using git:
+
+```commandline
+git clone https://github.com/AUTOMATIC1111/stable-diffusion-webui-aesthetic-gradients extensions/aesthetic-gradients
+```
+
+After running this command, make sure that you have `aesthetic-gradients` dir in webui's `extensions` directory and restart
+the UI. The interface for Aesthetic Gradients should appear exactly the same as it was.
+
+## Where is History/Image browser?!?!
+Image browser is now an extension. You can install it using git:
+
+```commandline
+git clone https://github.com/yfszzx/stable-diffusion-webui-images-browser extensions/images-browser
+```
+
+After running this command, make sure that you have `images-browser` dir in webui's `extensions` directory and restart
+the UI. The interface for Image browser should appear exactly the same as it was.
## Installation and Running
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.
-Alternatively, use Google Colab:
+Alternatively, use online services (like Google Colab):
-- [Colab, maintained by Akaibu](https://colab.research.google.com/drive/1kw3egmSn-KgWsikYvOMjJkVDsPLjEMzl)
-- [Colab, original by me, outdated](https://colab.research.google.com/drive/1Iy-xW9t1-OQWhb0hNxueGij8phCyluOh).
+- [List of Online Services](https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Online-Services)
### Automatic Installation on Windows
1. Install [Python 3.10.6](https://www.python.org/downloads/windows/), checking "Add Python to PATH"
diff --git a/extensions/put extensions here.txt b/extensions/put extensions here.txt
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/extensions/put extensions here.txt
diff --git a/javascript/aspectRatioOverlay.js b/javascript/aspectRatioOverlay.js
index 96f1c00d..66f26a22 100644
--- a/javascript/aspectRatioOverlay.js
+++ b/javascript/aspectRatioOverlay.js
@@ -3,12 +3,12 @@ let currentWidth = null;
let currentHeight = null;
let arFrameTimeout = setTimeout(function(){},0);
-function dimensionChange(e,dimname){
+function dimensionChange(e, is_width, is_height){
- if(dimname == 'Width'){
+ if(is_width){
currentWidth = e.target.value*1.0
}
- if(dimname == 'Height'){
+ if(is_height){
currentHeight = e.target.value*1.0
}
@@ -18,22 +18,13 @@ function dimensionChange(e,dimname){
return;
}
- var img2imgMode = gradioApp().querySelector('#mode_img2img.tabs > div > button.rounded-t-lg.border-gray-200')
- if(img2imgMode){
- img2imgMode=img2imgMode.innerText
- }else{
- return;
- }
-
- var redrawImage = gradioApp().querySelector('div[data-testid=image] img');
- var inpaintImage = gradioApp().querySelector('#img2maskimg div[data-testid=image] img')
-
var targetElement = null;
- if(img2imgMode=='img2img' && redrawImage){
- targetElement = redrawImage;
- }else if(img2imgMode=='Inpaint' && inpaintImage){
- targetElement = inpaintImage;
+ var tabIndex = get_tab_index('mode_img2img')
+ if(tabIndex == 0){
+ targetElement = gradioApp().querySelector('div[data-testid=image] img');
+ } else if(tabIndex == 1){
+ targetElement = gradioApp().querySelector('#img2maskimg div[data-testid=image] img');
}
if(targetElement){
@@ -98,22 +89,20 @@ onUiUpdate(function(){
var inImg2img = Boolean(gradioApp().querySelector("button.rounded-t-lg.border-gray-200"))
if(inImg2img){
let inputs = gradioApp().querySelectorAll('input');
- inputs.forEach(function(e){
- let parentLabel = e.parentElement.querySelector('label')
- if(parentLabel && parentLabel.innerText){
- if(!e.classList.contains('scrollwatch')){
- if(parentLabel.innerText == 'Width' || parentLabel.innerText == 'Height'){
- e.addEventListener('input', function(e){dimensionChange(e,parentLabel.innerText)} )
- e.classList.add('scrollwatch')
- }
- if(parentLabel.innerText == 'Width'){
- currentWidth = e.value*1.0
- }
- if(parentLabel.innerText == 'Height'){
- currentHeight = e.value*1.0
- }
- }
- }
+ inputs.forEach(function(e){
+ var is_width = e.parentElement.id == "img2img_width"
+ var is_height = e.parentElement.id == "img2img_height"
+
+ if((is_width || is_height) && !e.classList.contains('scrollwatch')){
+ e.addEventListener('input', function(e){dimensionChange(e, is_width, is_height)} )
+ e.classList.add('scrollwatch')
+ }
+ if(is_width){
+ currentWidth = e.value*1.0
+ }
+ if(is_height){
+ currentHeight = e.value*1.0
+ }
})
}
});
diff --git a/javascript/dragdrop.js b/javascript/dragdrop.js
index 070cf255..3ed1cb3c 100644
--- a/javascript/dragdrop.js
+++ b/javascript/dragdrop.js
@@ -43,7 +43,7 @@ function dropReplaceImage( imgWrap, files ) {
window.document.addEventListener('dragover', e => {
const target = e.composedPath()[0];
const imgWrap = target.closest('[data-testid="image"]');
- if ( !imgWrap && target.placeholder.indexOf("Prompt") == -1) {
+ if ( !imgWrap && target.placeholder && target.placeholder.indexOf("Prompt") == -1) {
return;
}
e.stopPropagation();
diff --git a/javascript/hints.js b/javascript/hints.js
index b98012f5..6ddd6aec 100644
--- a/javascript/hints.js
+++ b/javascript/hints.js
@@ -62,8 +62,8 @@ titles = {
"Interrogate": "Reconstruct prompt from existing image and put it into the prompt field.",
- "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], [prompt_words], [date], [datetime], [job_timestamp]; leave empty for default.",
- "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], [prompt_words], [date], [datetime], [job_timestamp]; leave empty for default.",
+ "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], [prompt_words], [date], [datetime], [datetime<Format>], [datetime<Format><Time Zone>], [job_timestamp]; leave empty for default.",
+ "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], [prompt_words], [date], [datetime], [datetime<Format>], [datetime<Format><Time Zone>], [job_timestamp]; leave empty for default.",
"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",
"Loopback": "Process an image, use it as an input, repeat.",
@@ -91,6 +91,8 @@ titles = {
"Weighted sum": "Result = A * (1 - M) + B * M",
"Add difference": "Result = A + (B - C) * M",
+
+ "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.",
}
diff --git a/javascript/images_history.js b/javascript/images_history.js
deleted file mode 100644
index f7d052c3..00000000
--- a/javascript/images_history.js
+++ /dev/null
@@ -1,206 +0,0 @@
-var images_history_click_image = function(){
- if (!this.classList.contains("transform")){
- var gallery = images_history_get_parent_by_class(this, "images_history_cantainor");
- var buttons = gallery.querySelectorAll(".gallery-item");
- var i = 0;
- var hidden_list = [];
- buttons.forEach(function(e){
- if (e.style.display == "none"){
- hidden_list.push(i);
- }
- i += 1;
- })
- if (hidden_list.length > 0){
- setTimeout(images_history_hide_buttons, 10, hidden_list, gallery);
- }
- }
- images_history_set_image_info(this);
-}
-
-var images_history_click_tab = function(){
- var tabs_box = gradioApp().getElementById("images_history_tab");
- if (!tabs_box.classList.contains(this.getAttribute("tabname"))) {
- gradioApp().getElementById(this.getAttribute("tabname") + "_images_history_renew_page").click();
- tabs_box.classList.add(this.getAttribute("tabname"))
- }
-}
-
-function images_history_disabled_del(){
- gradioApp().querySelectorAll(".images_history_del_button").forEach(function(btn){
- btn.setAttribute('disabled','disabled');
- });
-}
-
-function images_history_get_parent_by_class(item, class_name){
- var parent = item.parentElement;
- while(!parent.classList.contains(class_name)){
- parent = parent.parentElement;
- }
- return parent;
-}
-
-function images_history_get_parent_by_tagname(item, tagname){
- var parent = item.parentElement;
- tagname = tagname.toUpperCase()
- while(parent.tagName != tagname){
- console.log(parent.tagName, tagname)
- parent = parent.parentElement;
- }
- return parent;
-}
-
-function images_history_hide_buttons(hidden_list, gallery){
- var buttons = gallery.querySelectorAll(".gallery-item");
- var num = 0;
- buttons.forEach(function(e){
- if (e.style.display == "none"){
- num += 1;
- }
- });
- if (num == hidden_list.length){
- setTimeout(images_history_hide_buttons, 10, hidden_list, gallery);
- }
- for( i in hidden_list){
- buttons[hidden_list[i]].style.display = "none";
- }
-}
-
-function images_history_set_image_info(button){
- var buttons = images_history_get_parent_by_tagname(button, "DIV").querySelectorAll(".gallery-item");
- var index = -1;
- var i = 0;
- buttons.forEach(function(e){
- if(e == button){
- index = i;
- }
- if(e.style.display != "none"){
- i += 1;
- }
- });
- var gallery = images_history_get_parent_by_class(button, "images_history_cantainor");
- var set_btn = gallery.querySelector(".images_history_set_index");
- var curr_idx = set_btn.getAttribute("img_index", index);
- if (curr_idx != index) {
- set_btn.setAttribute("img_index", index);
- images_history_disabled_del();
- }
- set_btn.click();
-
-}
-
-function images_history_get_current_img(tabname, image_path, files){
- return [
- gradioApp().getElementById(tabname + '_images_history_set_index').getAttribute("img_index"),
- image_path,
- files
- ];
-}
-
-function images_history_delete(del_num, tabname, img_path, img_file_name, page_index, filenames, image_index){
- image_index = parseInt(image_index);
- var tab = gradioApp().getElementById(tabname + '_images_history');
- var set_btn = tab.querySelector(".images_history_set_index");
- var buttons = [];
- tab.querySelectorAll(".gallery-item").forEach(function(e){
- if (e.style.display != 'none'){
- buttons.push(e);
- }
- });
- var img_num = buttons.length / 2;
- if (img_num <= del_num){
- setTimeout(function(tabname){
- gradioApp().getElementById(tabname + '_images_history_renew_page').click();
- }, 30, tabname);
- } else {
- var next_img
- for (var i = 0; i < del_num; i++){
- if (image_index + i < image_index + img_num){
- buttons[image_index + i].style.display = 'none';
- buttons[image_index + img_num + 1].style.display = 'none';
- next_img = image_index + i + 1
- }
- }
- var bnt;
- if (next_img >= img_num){
- btn = buttons[image_index - del_num];
- } else {
- btn = buttons[next_img];
- }
- setTimeout(function(btn){btn.click()}, 30, btn);
- }
- images_history_disabled_del();
- return [del_num, tabname, img_path, img_file_name, page_index, filenames, image_index];
-}
-
-function images_history_turnpage(img_path, page_index, image_index, tabname){
- var buttons = gradioApp().getElementById(tabname + '_images_history').querySelectorAll(".gallery-item");
- buttons.forEach(function(elem) {
- elem.style.display = 'block';
- })
- return [img_path, page_index, image_index, tabname];
-}
-
-function images_history_enable_del_buttons(){
- gradioApp().querySelectorAll(".images_history_del_button").forEach(function(btn){
- btn.removeAttribute('disabled');
- })
-}
-
-function images_history_init(){
- var load_txt2img_button = gradioApp().getElementById('txt2img_images_history_renew_page')
- if (load_txt2img_button){
- for (var i in images_history_tab_list ){
- tab = images_history_tab_list[i];
- gradioApp().getElementById(tab + '_images_history').classList.add("images_history_cantainor");
- gradioApp().getElementById(tab + '_images_history_set_index').classList.add("images_history_set_index");
- gradioApp().getElementById(tab + '_images_history_del_button').classList.add("images_history_del_button");
- gradioApp().getElementById(tab + '_images_history_gallery').classList.add("images_history_gallery");
-
- }
- var tabs_box = gradioApp().getElementById("tab_images_history").querySelector("div").querySelector("div").querySelector("div");
- tabs_box.setAttribute("id", "images_history_tab");
- var tab_btns = tabs_box.querySelectorAll("button");
- for (var i in images_history_tab_list){
- var tabname = images_history_tab_list[i]
- tab_btns[i].setAttribute("tabname", tabname);
-
- // this refreshes history upon tab switch
- // until the history is known to work well, which is not the case now, we do not do this at startup
- //tab_btns[i].addEventListener('click', images_history_click_tab);
- }
- tabs_box.classList.add(images_history_tab_list[0]);
-
- // same as above, at page load
- //load_txt2img_button.click();
- } else {
- setTimeout(images_history_init, 500);
- }
-}
-
-var images_history_tab_list = ["txt2img", "img2img", "extras"];
-setTimeout(images_history_init, 500);
-document.addEventListener("DOMContentLoaded", function() {
- var mutationObserver = new MutationObserver(function(m){
- for (var i in images_history_tab_list ){
- let tabname = images_history_tab_list[i]
- var buttons = gradioApp().querySelectorAll('#' + tabname + '_images_history .gallery-item');
- buttons.forEach(function(bnt){
- bnt.addEventListener('click', images_history_click_image, true);
- });
-
- // same as load_txt2img_button.click() above
- /*
- var cls_btn = gradioApp().getElementById(tabname + '_images_history_gallery').querySelector("svg");
- if (cls_btn){
- cls_btn.addEventListener('click', function(){
- gradioApp().getElementById(tabname + '_images_history_renew_page').click();
- }, false);
- }*/
-
- }
- });
- mutationObserver.observe( gradioApp(), { childList:true, subtree:true });
-
-});
-
-
diff --git a/javascript/localization.js b/javascript/localization.js
index e6644635..f92d2d24 100644
--- a/javascript/localization.js
+++ b/javascript/localization.js
@@ -108,6 +108,9 @@ function processNode(node){
function dumpTranslations(){
dumped = {}
+ if (localization.rtl) {
+ dumped.rtl = true
+ }
Object.keys(original_lines).forEach(function(text){
if(dumped[text] !== undefined) return
@@ -129,6 +132,24 @@ onUiUpdate(function(m){
document.addEventListener("DOMContentLoaded", function() {
processNode(gradioApp())
+
+ if (localization.rtl) { // if the language is from right to left,
+ (new MutationObserver((mutations, observer) => { // wait for the style to load
+ mutations.forEach(mutation => {
+ mutation.addedNodes.forEach(node => {
+ if (node.tagName === 'STYLE') {
+ observer.disconnect();
+
+ for (const x of node.sheet.rules) { // find all rtl media rules
+ if (Array.from(x.media || []).includes('rtl')) {
+ x.media.appendMedium('all'); // enable them
+ }
+ }
+ }
+ })
+ });
+ })).observe(gradioApp(), { childList: true });
+ }
})
function download_localization() {
diff --git a/launch.py b/launch.py
index 7b15e78e..8affd410 100644
--- a/launch.py
+++ b/launch.py
@@ -111,7 +111,7 @@ def prepare_enviroment():
gfpgan_package = os.environ.get('GFPGAN_PACKAGE', "git+https://github.com/TencentARC/GFPGAN.git@8d2447a2d918f8eba5a4a01463fd48e45126a379")
clip_package = os.environ.get('CLIP_PACKAGE', "git+https://github.com/openai/CLIP.git@d50d76daa670286dd6cacf3bcd80b5e4823fc8e1")
- deepdanbooru_package = os.environ.get('DEEPDANBOORU_PACKAGE', "git+https://github.com/KichangKim/DeepDanbooru.git@edf73df4cdaeea2cf00e9ac08bd8a9026b7a7b26")
+ deepdanbooru_package = os.environ.get('DEEPDANBOORU_PACKAGE', "git+https://github.com/KichangKim/DeepDanbooru.git@d91a2963bf87c6a770d74894667e9ffa9f6de7ff")
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')
@@ -156,9 +156,15 @@ def prepare_enviroment():
if not is_installed("clip"):
run_pip(f"install {clip_package}", "clip")
- if (not is_installed("xformers") or reinstall_xformers) and xformers and platform.python_version().startswith("3.10"):
+ if (not is_installed("xformers") or reinstall_xformers) and xformers:
if platform.system() == "Windows":
- run_pip(f"install -U -I --no-deps {xformers_windows_package}", "xformers")
+ if platform.python_version().startswith("3.10"):
+ run_pip(f"install -U -I --no-deps {xformers_windows_package}", "xformers")
+ else:
+ print("Installation of xformers is not supported in this version of Python.")
+ print("You can also check this and build manually: https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Xformers#building-xformers-on-windows-by-duckness")
+ if not is_installed("xformers"):
+ exit(0)
elif platform.system() == "Linux":
run_pip("install xformers", "xformers")
diff --git a/localizations/ar_AR.json b/localizations/ar_AR.json
new file mode 100644
index 00000000..1195a8e9
--- /dev/null
+++ b/localizations/ar_AR.json
@@ -0,0 +1,456 @@
+{
+ "rtl": true,
+ "⤡": "⤡",
+ "⊞": "⊞",
+ "×": "×",
+ "❮": "❮",
+ "❯": "❯",
+ "Loading...": "جار التحميل...",
+ "view": "معاينة",
+ "api": "api",
+ "•": "•",
+ "built with gradio": "مبني باستخدام Gradio",
+ "Stable Diffusion checkpoint": "نماذج الانتشار المستقر",
+ "txt2img": "نص لصورة",
+ "img2img": "صورة لصورة",
+ "Extras": "الإضافات",
+ "PNG Info": "معلومات PNG",
+ "Checkpoint Merger": "دمج النماذج",
+ "Train": "التدريب",
+ "Create aesthetic embedding": "Create aesthetic embedding",
+ "Image Browser": "مستعرض الصور",
+ "Settings": "الإعدادات",
+ "Prompt": "الموجه",
+ "Negative prompt": "الموجه السلبي",
+ "Run": "تشغيل",
+ "Skip": "تخطي",
+ "Interrupt": "إيقاف",
+ "Generate": "إنشاء",
+ "Style 1": "نمط 1",
+ "Style 2": "نمط 2",
+ "Label": "الوسم",
+ "File": "ملف",
+ "Drop File Here": "اسحب الملف هنا",
+ "-": "-",
+ "or": "أو",
+ "Click to Upload": "انقر للتحميل",
+ "Image": "صورة",
+ "Check progress": "تحقق من التقدم",
+ "Check progress (first)": "تحقق من التقدم (الأول)",
+ "Sampling Steps": "خطوات أخذ العينة",
+ "Sampling method": "نظام أخذ العينات",
+ "Euler a": "Euler a",
+ "Euler": "Euler",
+ "LMS": "LMS",
+ "Heun": "Heun",
+ "DPM2": "DPM2",
+ "DPM2 a": "DPM2 a",
+ "DPM fast": "DPM fast",
+ "DPM adaptive": "DPM adaptive",
+ "LMS Karras": "LMS Karras",
+ "DPM2 Karras": "DPM2 Karras",
+ "DPM2 a Karras": "DPM2 a Karras",
+ "DDIM": "DDIM",
+ "PLMS": "PLMS",
+ "Width": "العرض",
+ "Height": "الارتفاع",
+ "Restore faces": "ترميم الوجوه",
+ "Tiling": "تبليط",
+ "Highres. fix": "إصلاح الصور عالية الدقة",
+ "Firstpass width": "عرض المرور الأول",
+ "Firstpass height": "ارتفاع المرور الأول",
+ "Denoising strength": "قوة تقليل الضوضاء",
+ "Batch count": "عدد الدُفعات",
+ "Batch size": "حجم الدفعة",
+ "CFG Scale": "مقياس التقارب من الموجه (CFG)",
+ "Seed": "البذرة",
+ "Extra": "إضافي",
+ "Variation seed": "تباين البذرة",
+ "Variation strength": "قوة التباين",
+ "Resize seed from width": "تغيير حجم البذرة من العرض",
+ "Resize seed from height": "تغيير حجم البذرة من الارتفاع",
+ "Open for Clip Aesthetic!": "Open for Clip Aesthetic!",
+ "▼": "▼",
+ "Aesthetic weight": "Aesthetic weight",
+ "Aesthetic steps": "Aesthetic steps",
+ "Aesthetic learning rate": "Aesthetic learning rate",
+ "Slerp interpolation": "Slerp interpolation",
+ "Aesthetic imgs embedding": "Aesthetic imgs embedding",
+ "None": "لايوجد",
+ "Aesthetic text for imgs": "Aesthetic text for imgs",
+ "Slerp angle": "Slerp angle",
+ "Is negative text": "Is negative text",
+ "Script": "سكريبت",
+ "Prompt matrix": "مصفوفة الموجهات",
+ "Prompts from file or textbox": "موجهات من ملف أو مربع النص",
+ "X/Y plot": "الرسم البياني X/Y",
+ "Put variable parts at start of prompt": "ضع الأجزاء المتغيرة في بداية الموجه",
+ "Show Textbox": "إظهار مربع النص",
+ "File with inputs": "ملف يحتوي المدخلات",
+ "Prompts": "الموجهات",
+ "X type": "نوع X",
+ "Nothing": "لا شئ",
+ "Var. seed": "تغير البذرة",
+ "Var. strength": "قوة التغيير",
+ "Steps": "الخطوات",
+ "Prompt S/R": "موجه S / R",
+ "Prompt order": "ترتيب الموجهات",
+ "Sampler": "نظام أخذ العينات",
+ "Checkpoint name": "اسم النموذج",
+ "Hypernetwork": "الشبكة الفائقة",
+ "Hypernet str.": "قوة الشبكة الفائقة",
+ "Sigma Churn": "دفع سيجما",
+ "Sigma min": "أصغر سيجما",
+ "Sigma max": "أكبر سيجما",
+ "Sigma noise": "ضجة سيجما",
+ "Eta": "الوقت المتوقع",
+ "Clip skip": "تخطي Clip",
+ "Denoising": "تقليل الضوضاء",
+ "X values": "قيم X",
+ "Y type": "نوع Y",
+ "Y values": "قيم Y",
+ "Draw legend": "ارسم مفتاح التوضيح",
+ "Include Separate Images": "قم بتضمين الصور منفصلة",
+ "Keep -1 for seeds": "احتفظ بـقيمة -1 للبذور",
+ "Drop Image Here": "إسقاط الصورة هنا",
+ "Save": "حفظ",
+ "Send to img2img": "أرسل إلى صورة لصورة",
+ "Send to inpaint": "أرسل إلى إعادة الرسم الجزئي",
+ "Send to extras": "أرسل إلى الإضافات",
+ "Make Zip when Save?": "إنشاء ملف مضغوط عند الحفظ؟",
+ "Textbox": "مربع النص",
+ "Interrogate\nCLIP": "استجواب\n CLIP",
+ "Inpaint": "إعادة الرسم الجزئي",
+ "Batch img2img": "دفعات صورة لصورة",
+ "Image for img2img": "صورة (صورة لصورة)",
+ "Image for inpainting with mask": "صورة (إعادة الرسم الجزئي)",
+ "Mask": "القناع",
+ "Mask blur": "ضبابية القناع",
+ "Mask mode": "أسلوب القناع",
+ "Draw mask": "رسم القناع",
+ "Upload mask": "تحميل القناع",
+ "Masking mode": "أسلوب التقنيع",
+ "Inpaint masked": "إعادة الرسم الجزئي (المنطقة المقنعة)",
+ "Inpaint not masked": "إعادة الرسم الجزئي (المنطقة الغير مقنعة)",
+ "Masked content": "المحتوى المقنع",
+ "fill": "الملأ",
+ "original": "الأصلي",
+ "latent noise": "الضوضاء الكامنة",
+ "latent nothing": "لا شيء كامن",
+ "Inpaint at full resolution": "إعادة الرسم الجزئي بدقة كاملة",
+ "Inpaint at full resolution padding, pixels": "إعادة الرسم الجزئي بدقة كاملة, الحشو, بيكسل",
+ "Process images in a directory on the same machine where the server is running.": "معالجة الصور في المجلد على نفس الجهاز حيث يتم تشغيل الخادم.",
+ "Use an empty output directory to save pictures normally instead of writing to the output directory.": "استخدم مجلد إخراج فارغ لحفظ الصور بشكل طبيعي بدلاً من الكتابة إلى مجلد المخرجات.",
+ "Input directory": "مجلد المدخلات",
+ "Output directory": "مجلد المخرجات",
+ "Resize mode": "وضعية تغيير الحجم",
+ "Just resize": "تغييير الحجم فقط",
+ "Crop and resize": "اقتصاص وتغيير الحجم",
+ "Resize and fill": "تغيير الحجم والتعبئة",
+ "img2img alternative test": "صورة لصورة البديلة",
+ "Loopback": "الحلقة الراجعة",
+ "Outpainting mk2": "الرسم الخارجي نسخة 2",
+ "Poor man's outpainting": "الرسم الخارجي للفقراء",
+ "SD upscale": "ترقية الانتشار المستقر",
+ "should be 2 or lower.": "should be 2 or lower.",
+ "Override `Sampling method` to Euler?(this method is built for it)": "Override `Sampling method` to Euler?(this method is built for it)",
+ "Override `prompt` to the same value as `original prompt`?(and `negative prompt`)": "Override `prompt` to the same value as `original prompt`?(and `negative prompt`)",
+ "Original prompt": "Original prompt",
+ "Original negative prompt": "Original negative prompt",
+ "Override `Sampling Steps` to the same value as `Decode steps`?": "Override `Sampling Steps` to the same value as `Decode steps`?",
+ "Decode steps": "Decode steps",
+ "Override `Denoising strength` to 1?": "Override `Denoising strength` to 1?",
+ "Decode CFG scale": "Decode CFG scale",
+ "Randomness": "Randomness",
+ "Sigma adjustment for finding noise for image": "Sigma adjustment for finding noise for image",
+ "Loops": "Loops",
+ "Denoising strength change factor": "معامل قوة تقليل الضوضاء",
+ "Recommended settings: Sampling Steps: 80-100, Sampler: Euler a, Denoising strength: 0.8": "الإعدادات الموصى بها: خطوات أخذ العينات: 80-100 ، طريقة أخذ العينات: Euler a ، تقليل الضوضاء: 0.8",
+ "Pixels to expand": "عدد البكسل للتوسيع",
+ "Outpainting direction": "إتجاه الرسم الخارجي",
+ "left": "يسار",
+ "right": "يمين",
+ "up": "فوق",
+ "down": "تحت",
+ "Fall-off exponent (lower=higher detail)": "أس التناقص (الأدنى = تفاصيل أعلى)",
+ "Color variation": "اختلاف اللون",
+ "Will upscale the image to twice the dimensions; use width and height sliders to set tile size": "سيقوم بترقية الصورة إلى ضعف الأبعاد ؛ استخدم شريط تمرير العرض والارتفاع لضبط حجم التبليط",
+ "Tile overlap": "تداخل التبليط",
+ "Upscaler": "المرقي",
+ "Lanczos": "Lanczos",
+ "Single Image": "صورة واحدة",
+ "Batch Process": "معالجة الدفعات",
+ "Batch from Directory": "دفعة من المجلد",
+ "Source": "مصدر",
+ "Show result images": "إظهار نتائج الصور ",
+ "Scale by": "رفع الحجم بمقدار",
+ "Scale to": "رفع الحجم إلى",
+ "Resize": "تغيير الحجم",
+ "Crop to fit": "اقتصاص للتوافق",
+ "Upscaler 2 visibility": "إظهار المرقي 2",
+ "GFPGAN visibility": "إظهار GFPGAN",
+ "CodeFormer visibility": "إظهار CodeFormer",
+ "CodeFormer weight (0 = maximum effect, 1 = minimum effect)": "وزن CodeFormer (0 = أقصى تأثير ، 1 = تأثير أدنى)",
+ "Open output directory": "افتح مجلد المخرجات",
+ "Send to txt2img": "أرسل إلى كتابة لصورة",
+ "A merger of the two checkpoints will be generated in your": "سيتم إنشاء نموذجمدمج من النموذجين في",
+ "checkpoint": "النموذج",
+ "directory.": "المجلد.",
+ "Primary model (A)": "النموذج الأساسي (أ)",
+ "Secondary model (B)": "النموذج الثانوي (ب)",
+ "Tertiary model (C)": "النموذج الثالث (ج)",
+ "Custom Name (Optional)": "اسم مخصص (اختياري)",
+ "Multiplier (M) - set to 0 to get model A": "المضاعف (M) - اضبط على 0 للحصول على النموذج أ",
+ "Interpolation Method": "طريقة الاستنباط",
+ "Weighted sum": "المجموع الموزون",
+ "Add difference": "أضافة الاختلاف",
+ "Save as float16": "حفظ float16",
+ "See": "شاهد",
+ "wiki": "ويكي",
+ "for detailed explanation.": "للحصول على شرح مفصل.",
+ "Create embedding": "إنشاء التضمين",
+ "Create hypernetwork": "إنشاء شبكة فائقة",
+ "Preprocess images": "تجهيز الصور",
+ "Name": "الاسم",
+ "Initialization text": "نص التهيئة",
+ "Number of vectors per token": "عدد المتجهات لكل رمز",
+ "Overwrite Old Embedding": "الكتابة فوق التضمين القديم",
+ "Modules": "الوحدات",
+ "Enter hypernetwork layer structure": "أدخل بنية طبقة الشبكة الفائقة",
+ "Select activation function of hypernetwork": "حدد وظيفة تنشيط الشبكة الفائقة",
+ "linear": "خطي (Linear)",
+ "relu": "الوحدة الخطية المعدلة (Relu)",
+ "leakyrelu": "الوحدة الخطية المعدلة المسربة (Leakyrelu)",
+ "elu": "الوحدة الأسية الخطية (Elu)",
+ "swish": "Swish",
+ "Add layer normalization": "أضف طبقة التسوية",
+ "Use dropout": "استخدم الهبوط",
+ "Overwrite Old Hypernetwork": "الكتابة فوق الشبكة الفائقة القديمة",
+ "Source directory": "مجلد المصدر",
+ "Destination directory": "مجلد النتائج",
+ "Existing Caption txt Action": "الإجراء النصي للتعليق المتوفر",
+ "ignore": "تجاهل",
+ "copy": "نسخ",
+ "prepend": "أضف قبل",
+ "append": "ألحق",
+ "Create flipped copies": "قم بإنشاء نسخ مقلوبة",
+ "Split oversized images": "تقسيم الصور كبيرة الحجم",
+ "Use BLIP for caption": "استخدم BLIP للتعليق",
+ "Use deepbooru for caption": "استخدم deepbooru للتعليق",
+ "Split image threshold": "حد تقسيم الصورة",
+ "Split image overlap ratio": "نسبة تداخل الصورة المنقسمة",
+ "Preprocess": "تجهيز الصور",
+ "Train an embedding or Hypernetwork; you must specify a directory with a set of 1:1 ratio images": "تدريب التضمين أو الشبكة الفائقة ؛ يجب تحديد مجلد بمجموعة من الصور بنسبة أبعاد 1: 1",
+ "[wiki]": "[ويكي]",
+ "Embedding": "التضمين",
+ "Embedding Learning rate": "معدل تعلم التضمين",
+ "Hypernetwork Learning rate": "معدل تعلم الشبكة الفائقة",
+ "Dataset directory": "مجلد مجموعة البيانات",
+ "Log directory": "مجلد السجل",
+ "Prompt template file": "ملف قالب الموجهات",
+ "Max steps": "الخطوات القصوى",
+ "Save an image to log directory every N steps, 0 to disable": "حفظ صورة في مجلد السجل كل N خطوات ، 0 للتعطيل",
+ "Save a copy of embedding to log directory every N steps, 0 to disable": "حفظ نسخة من التضمين في مجلد السجل كل N خطوات ، 0 للتعطيل",
+ "Save images with embedding in PNG chunks": "حفظ التضمين مع الصور في أجزاء PNG",
+ "Read parameters (prompt, etc...) from txt2img tab when making previews": "قراءة المتغيرات (الموجه ، إلخ ...) من علامة تبويب نص لصورة عند إجراء المعاينات",
+ "Train Hypernetwork": "تدريب الشبكة الفائقة",
+ "Train Embedding": "تدريب التضمين",
+ "Create an aesthetic embedding out of any number of images": "Create an aesthetic embedding out of any number of images",
+ "Create images embedding": "Create images embedding",
+ "extras": "إضافات",
+ "favorites": "المفضلة",
+ "custom fold": "custom fold",
+ "Load": "تحميل",
+ "Images directory": "مجلد الصور",
+ "Prev batch": "الدفعة السابقة",
+ "Next batch": "الدفعة التالية",
+ "First Page": "الصفحة الأولى",
+ "Prev Page": "الصفحة السابقة",
+ "Page Index": "فهرس الصفحات",
+ "Next Page": "الصفحة التالية",
+ "End Page": "صفحة النهاية",
+ "number of images to delete consecutively next": "عدد الصور المطلوب حذفها على التوالي بعد ذلك",
+ "Delete": "حذف",
+ "Generate Info": "معلومات الإنشاء",
+ "File Name": "اسم الملف",
+ "Collect": "جمع",
+ "Refresh page": "إعادة تحميل الصفحة",
+ "Date to": "التاريخ إلى",
+ "Number": "الرقم",
+ "set_index": "وضع الفهرس",
+ "Checkbox": "صندوق اختيار",
+ "Apply settings": "تطبيق الإعدادات",
+ "Saving images/grids": "حفظ الصور / الإطار الشبكي",
+ "Always save all generated images": "احفظ دائمًا جميع الصور التي تم إنشائها",
+ "File format for images": "تنسيق ملفات الصور",
+ "Images filename pattern": "نمط اسم ملفات الصور",
+ "Add number to filename when saving": "Add number to filename when saving",
+ "Always save all generated image grids": "احفظ دائمًا جميع الإطارات الشبكية للصور التي تم إنشاؤها",
+ "File format for grids": "تنسيق ملفات الإطارات الشبكية",
+ "Add extended info (seed, prompt) to filename when saving grid": "أضف معلومات إضافية (البذرة ، الموجه) إلى اسم الملف عند حفظ الإطار الشبكي",
+ "Do not save grids consisting of one picture": "لا تحفظ الإطارات الشبكية التي تتكون من صورة واحدة",
+ "Prevent empty spots in grid (when set to autodetect)": "منع المناطق الفارغة في الإطار الشبكي (عند الضبط على الاكتشاف التلقائي)",
+ "Grid row count; use -1 for autodetect and 0 for it to be same as batch size": "عدد صفوف الإطار الشبكي استخدم -1 للاكتشاف التلقائي و 0 ليكون نفس حجم الدُفعة",
+ "Save text information about generation parameters as chunks to png files": "احفظ معلومات نصية حول متغيرات الإنشاء كمقاطع في ملفات png",
+ "Create a text file next to every image with generation parameters.": "قم بإنشاء ملف نصي بجوار كل صورة باستخدام متغيرات الإنشاء.",
+ "Save a copy of image before doing face restoration.": "احفظ نسخة من الصورة قبل القيام بترميم الوجوه.",
+ "Quality for saved jpeg images": "جودة الصور المحفوظة بتنسيق jpeg",
+ "If PNG image is larger than 4MB or any dimension is larger than 4000, downscale and save copy as JPG": "إذا كانت صورة PNG أكبر من 4 ميجابايت أو كان أي بُعد أكبر من 4000 ، قم بتقليل حجم الصورة وحفظها بتنسيق JPG",
+ "Use original name for output filename during batch process in extras tab": "استخدم الاسم الأصلي لاسم ملف الإخراج أثناء عملية الدُفعات في علامة تبويب الإضافات",
+ "When using 'Save' button, only save a single selected image": "عند استخدام زر 'حفظ' ، احفظ فقط صورة واحدة محددة",
+ "Do not add watermark to images": "لا تقم بإضافة العلامة المائية للصور",
+ "Paths for saving": "مسارات الحفظ",
+ "Output directory for images; if empty, defaults to three directories below": "مجلد المخرجات للصور ؛ إذا كان فارغا ، يتم تعيينه افتراضيًا إلى المجلدات الثلاثة أدناه",
+ "Output directory for txt2img images": "مجلد المخرجات لصور نص لصورة",
+ "Output directory for img2img images": "مجلد المخرجات لصور صورة لصورة",
+ "Output directory for images from extras tab": "مجلد المخرجات لصور علامة تبويب الإضافات",
+ "Output directory for grids; if empty, defaults to two directories below": "مجلد المخرجات للإطارات الشبكية ؛ إذا كان فارغا ، يتم تعيينه افتراضيًا إلى المجلدين أدناه",
+ "Output directory for txt2img grids": "مجلد المخرجات للإطارات الشبكية نص لصورة",
+ "Output directory for img2img grids": "مجلد المخرجات للإطارات الشبكية صورة لصورة",
+ "Directory for saving images using the Save button": "مجلد لحفظ الصور باستخدام زر حفظ",
+ "Saving to a directory": "يتم الحفظ إلى المجلد..",
+ "Save images to a subdirectory": "حفظ الصور في مجلد فرعي",
+ "Save grids to a subdirectory": "حفظ الإطارات الشبكية في مجلد فرعي",
+ "When using \"Save\" button, save images to a subdirectory": "احفظ الصور في مجلد فرعي عند الضغط على زر الحفظ",
+ "Directory name pattern": "نمط اسم المجلد",
+ "Max prompt words for [prompt_words] pattern": "أقصى عدد لكلمات التوجيه لنمط [كلمات_التوجيه]",
+ "Upscaling": "الارتقاء",
+ "Tile size for ESRGAN upscalers. 0 = no tiling.": "حجم التبليط لترقيات ESRGAN, القيمة 0= لا يوجد تبليط.",
+ "Tile overlap, in pixels for ESRGAN upscalers. Low values = visible seam.": "تداخل المربعات ، بالبكسل لمرقي ESRGAN. القيم المنخفضة = تداخل مرئي.",
+ "Tile size for all SwinIR.": "حجم التليط لجميع عمليات SwinIR.",
+ "Tile overlap, in pixels for SwinIR. Low values = visible seam.": "تداخل المربعات بالبكسل لـ SwinIR. القيم المنخفضة = تداخل مرئي.",
+ "LDSR processing steps. Lower = faster": "خطوات معالجة LDSR. أقل = أسرع",
+ "Upscaler for img2img": "المرقي لصورة لصورة",
+ "Upscale latent space image when doing hires. fix": "ترقية صورة الفضاء الكامن عند التعيينات. تصليح",
+ "Face restoration": "ترميم الوجوه",
+ "CodeFormer weight parameter; 0 = maximum effect; 1 = minimum effect": "متغيرات وزن CodeFormer ؛ 0 = أقصى تأثير ؛ 1 = الحد الأدنى من التأثير",
+ "Move face restoration model from VRAM into RAM after processing": "انقل نموذج استعادة الوجوه من VRAM إلى RAM بعد المعالجة",
+ "System": "نظام",
+ "VRAM usage polls per second during generation. Set to 0 to disable.": "استطلاعات استخدام VRAM في الثانية أثناء الإنشاء. اضبط على 0 للتعطيل.",
+ "Always print all generation info to standard output": "قم دائمًا بطباعة جميع معلومات الإنشاء إلى المخرج القياسي",
+ "Add a second progress bar to the console that shows progress for an entire job.": "أضف شريط تقدم آخر إلى وحدة التحكم يُظهر التدقم الكلي للمهمة.",
+ "Training": "التدريب",
+ "Move VAE and CLIP to RAM when training hypernetwork. Saves VRAM.": "تفريغ VAE و CLIP من VRAM عند التدريب",
+ "Filename word regex": "اسم ملف كلمات regex",
+ "Filename join string": "سلسلة أحرف دمج أسماء الملفات",
+ "Number of repeats for a single input image per epoch; used only for displaying epoch number": "عدد التكرارات لصورة إدخال واحدة لكل حقبة ؛ تستخدم فقط لعرض رقم الحقبة",
+ "Save an csv containing the loss to log directory every N steps, 0 to disable": "حفظ ملف csv يحتوي على الخسارة إلى مجلد السجل كل N خطوات ، 0 للتعطيل",
+ "Stable Diffusion": "انتشار مستقر",
+ "Checkpoints to cache in RAM": "التخزين المؤقت للنماذج في RAM",
+ "Hypernetwork strength": "قوة الشبكة الفائقة",
+ "Apply color correction to img2img results to match original colors.": "قم بتطبيق تصحيح الألوان على نتائج صورة لصورة لمطابقة الألوان الأصلية.",
+ "Save a copy of image before applying color correction to img2img results": "احفظ نسخة من الصورة قبل تطبيق تصحيح الألوان على نتائج صورة لصورة",
+ "With img2img, do exactly the amount of steps the slider specifies (normally you'd do less with less denoising).": "باستخدام صورة لصورة ، قم بالضبط بعدد الخطوات التي يحددها شريط التمرير (عادةً ما سيكون أقل مع تقليل التشويش).",
+ "Enable quantization in K samplers for sharper and cleaner results. This may change existing seeds. Requires restart to apply.": "تمكين تكميم عينات K للحصول على نتائج أوضح وأنظف. هذا قد يغير البذرة المستخدمة. يتطلب إعادة التشغيل للتطبيق.",
+ "Emphasis: use (text) to make model pay more attention to text and [text] to make it pay less attention": "التأكيد: استخدم (النص) لجعل النموذج يولي مزيدًا من الاهتمام للنص و استخدم [النص] لجعل النموذج يولي اهتمامًا أقل للنص",
+ "Use old emphasis implementation. Can be useful to reproduce old seeds.": "استخدم طريقة التأكيد القديمة. يمكن أن يكون مفيدًا لإعادة إنتاج البذور القديمة.",
+ "Make K-diffusion samplers produce same images in a batch as when making a single image": "اجعل انظمة أخذ عينات الانتشار K تنتج نفس الصور في الدفعات كما هو الحال عند إنشاء صورة واحدة",
+ "Increase coherency by padding from the last comma within n tokens when using more than 75 tokens": "زيادة التناسق عن طريق المساحة المتروكة من الفاصلة الأخيرة ضمن عدد n من الرموز المميزة عند استخدام أكثر من 75 رمزًا مميزًا",
+ "Filter NSFW content": "تصفية المحتوى الإباحي",
+ "Stop At last layers of CLIP model": "توقف عند آخر طبقات نموذج CLIP",
+ "Interrogate Options": "خيارات الاستجواب",
+ "Interrogate: keep models in VRAM": "الاستجواب: احتفظ بالنماذج في VRAM",
+ "Interrogate: use artists from artists.csv": "الاستجواب: استخدم قائمة الفنانين من ملف artists.csv",
+ "Interrogate: include ranks of model tags matches in results (Has no effect on caption-based interrogators).": "الاستجواب: قم بتضمين رتب علامات النموذج في النتائج (ليس له تأثير على الاستجواب المستند إلى التعليقات).",
+ "Interrogate: num_beams for BLIP": "الاستجواب: عدد الحزم لـ BLIP",
+ "Interrogate: minimum description length (excluding artists, etc..)": "الاستجواب: الحد الأدنى لطول الوصف (باستثناء الفنانين ،إلخ..)",
+ "Interrogate: maximum description length": "الاستجواب: الحد الأقصى لطول الوصف",
+ "CLIP: maximum number of lines in text file (0 = No limit)": "CLIP: أقصى عدد من الأسطر في الملف النصي (0 = بلا حدود)",
+ "Interrogate: deepbooru score threshold": "الاستجواب: عتبة درجات deepbooru",
+ "Interrogate: deepbooru sort alphabetically": "الاستجواب: الترتيب الأبجدي لـ deepbooru",
+ "use spaces for tags in deepbooru": "استخدام مسافات للعلامات في deepbooru",
+ "escape (\\) brackets in deepbooru (so they are used as literal brackets and not for emphasis)": "تجاهل الأقواس عند استخدام deepbooru (كي لا تعامل كأقواس التشديد)",
+ "User interface": "واجهة المستخدم",
+ "Show progressbar": "إظهار شريط التقدم",
+ "Show image creation progress every N sampling steps. Set 0 to disable.": "إظهار تقدم إنشاء الصورة لكل N خطوة من خطوات أخذ العينات. قم بتعيين 0 للتعطيل.",
+ "Show previews of all images generated in a batch as a grid": "إظهار معاينة لجميع الصور التي يتم إنشائها في الدفعة كإطار شبكي",
+ "Show grid in results for web": "إظهار الإطار الشبكي في نتائج الويب",
+ "Do not show any images in results for web": "لا تظهر أي صور في نتائج الويب",
+ "Add model hash to generation information": "أضف معلومات الهاش للنموذج إلى معلومات الإنشاء",
+ "Add model name to generation information": "أضف اسم النموذج إلى معلومات الإنشاء",
+ "When reading generation parameters from text into UI (from PNG info or pasted text), do not change the selected model/checkpoint.": "عند قراءة متغيرات الإنشاء من النص إلى واجهة المستخدم (من معلومات PNG أو النص الملصق) ، لا تقم بتغيير النموذج",
+ "Font for image grids that have text": "الخط المستخدم للإطارات الشبكية للصور التي تحتوي على نص",
+ "Enable full page image viewer": "تفعيل عارض الصور ذو الصفحة الكاملة",
+ "Show images zoomed in by default in full page image viewer": "إظهار الصور التي تم تكبيرها بشكل افتراضي في عارض الصور ذو الصفحة الكاملة",
+ "Show generation progress in window title.": "إظهار تقدم الإنشاء في عنوان الشاشة.",
+ "Quicksettings list": "قائمة الإعدادات السريعة",
+ "Localization (requires restart)": "الترجمة (يتطلب إعادة التشغيل)",
+ "Sampler parameters": "متغيرات أنظمة اخذ العينات",
+ "Hide samplers in user interface (requires restart)": "إخفاء أنظمة أخذ العينات في واجهة المستخدم (يتطلب إعادة التشغيل)",
+ "eta (noise multiplier) for DDIM": "الوقت المتبقي (مضاعف الضوضاء) لـ DDIM",
+ "eta (noise multiplier) for ancestral samplers": "الوقت المتبقي (مضاعف الضوضاء) لأنظمة أخذ العينات التي تعتمد على الأجداد",
+ "img2img DDIM discretize": "تفصل DDIM لصورة لصورة",
+ "uniform": "التوحيد",
+ "quad": "رباعية",
+ "sigma churn": "دفع سيجما",
+ "sigma tmin": "سيجما tmin",
+ "sigma noise": "ضجيج سيجما",
+ "Eta noise seed delta": "الوقت المتوقع لديلتا بذرة الضجيج ",
+ "Images Browser": "مستعرض الصور",
+ "Preload images at startup": "تحميل الصور مسبقًا عند بدء التشغيل",
+ "Number of columns on the page": "Number of columns on the page",
+ "Number of rows on the page": "Number of rows on the page",
+ "Minimum number of pages per load": "الحد الأدنى لعدد الصفحات لكل تحميل",
+ "Request browser notifications": "طلب إشعارات المتصفح",
+ "Download localization template": "تنزيل نموذج الترجمة",
+ "Reload custom script bodies (No ui updates, No restart)": "إعادة تحميل السكريبتات المخصصة (لا توجد تحديثات لواجهة المستخدم ، لا إعادة تشغيل)",
+ "Restart Gradio and Refresh components (Custom Scripts, ui.py, js and css only)": "أعادة تشغيل Gradio و تحديث مكونات واجهة الاستخدام (السكريبتات و ui.py و js و css فقط)",
+ "Prompt (press Ctrl+Enter or Alt+Enter to generate)": "الموجه (اضغط على Ctrl + Enter أو Alt + Enter للإنشاء)",
+ "Negative prompt (press Ctrl+Enter or Alt+Enter to generate)": "الموجه السلبي (اضغط على Ctrl + Enter أو Alt + Enter للإنشاء)",
+ "Add a random artist to the prompt.": "أضف فنانًا عشوائيًا إلى الموجه.",
+ "Read generation parameters from prompt or last generation if prompt is empty into user interface.": "قراءة متغيرات الإنشاء من الموجه أو الإنشاء الأخير إذا كان الموجه فارغا في واجهة المستخدم.",
+ "Save style": "حفظ النمط",
+ "Apply selected styles to current prompt": "تطبيق الأنماط المحددة للموجه الحالي",
+ "Stop processing current image and continue processing.": "توقف عن معالجة الصورة الحالية واستمر في المعالجة.",
+ "Stop processing images and return any results accumulated so far.": "توقف عن معالجة الصور وقم بإرجاع أي نتائج متراكمة حتى الآن.",
+ "Style to apply; styles have components for both positive and negative prompts and apply to both": "النمط المطلوب تطبيقه ؛ الأنماط لها مكونات لكل من الموجهات الإيجابية والسلبية وتنطبق على كليهما",
+ "Do not do anything special": "لا تفعل أي شيء خاص",
+ "Which algorithm to use to produce the image": "الخوارزمية التي يجب استخدامها لإنتاج الصورة",
+ "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": "Euler Ancestral - مبدع جدًا ، يمكن لكل منها الحصول على صورة مختلفة تمامًا اعتمادًا على عدد الخطوات ، تعيين الخطوات على أعلى من 30-40 لا يعطي نتيجة مفيدة",
+ "Denoising Diffusion Implicit Models - best at inpainting": "نماذج تقليل التشويش الضمني - أفضل اسخدام في الرسم الجزئي",
+ "Produce an image that can be tiled.": "أنتج صورة يمكن تبليطها.",
+ "Use a two step process to partially create an image at smaller resolution, upscale, and then improve details in it without changing composition": "استخدم عملية من خطوتين لإنشاء صورة جزئيًا بدقة أقل ثم ترقيتها و تحسين تفاصيلها دون تغيير التكوين",
+ "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.": "يحدد مدى ضآلة احترام الخوارزمية لمحتوى الصورة. عند 0 ، لن يتغير شيء ، وعند 1 ستحصل على صورة لا صلة لها بالصورة الأصلية. مع وجود قيم أقل من 1.0 ، المعالجة ستأخذ خطوات أقل مما يحدده شريط تمرير خطوات المعالجة.",
+ "How many batches of images to create": "كم عدد دفعات الصور التي يتم إنشائها",
+ "How many image to create in a single batch": "كم صورة يتم إنشائها دفعة واحدة",
+ "Classifier Free Guidance Scale - how strongly the image should conform to prompt - lower values produce more creative results": "مقياس التوجيه الحر للمصنف - إلى أي مدى يجب أن تتوافق الصورة مع الموجه - القيم المنخفضة تنتج نتائج أكثر إبداعًا",
+ "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": "القيمة التي تحدد ناتج منشئ الأرقام العشوائية - إذا قمت بإنشاء صورة بنفس المتغيرات و بذرة الصورة ، فستحصل على نفس النتيجة",
+ "Set seed to -1, which will cause a new random number to be used every time": "عيّن البذرة إلى -1 ، مما سيؤدي إلى استخدام رقم عشوائي جديد في كل مرة",
+ "Reuse seed from last generation, mostly useful if it was randomed": "إعادة استخدام البذرة من الإنشاء الأخير ، وتكون مفيدة في الغالب إذا كانت عشوائية",
+ "Seed of a different picture to be mixed into the generation.": "استخدام بذرة من صورة مختلفة ليتم مزجها في الإنشاء.",
+ "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).": "ما مدى قوة التباين عند الإنشاء. 0 ، لن يكون هناك أي تأثير. 1 ، ستحصل على الصورة الكاملة ببذور التباين (باستثناء أنظمة عينات الأسلاف ، حيث ستحصل على شيء ما فقط).",
+ "Make an attempt to produce a picture similar to what would have been produced with same seed at specified resolution": "قم بمحاولة لإنتاج صورة مشابهة لما تم إنتاجه بنفس البذرة بناءا على دقة محددة",
+ "This text is used to rotate the feature space of the imgs embs": "This text is used to rotate the feature space of the imgs embs",
+ "Separate values for X axis using commas.": "افصل بين قيم المحور X باستخدام الفواصل.",
+ "Separate values for Y axis using commas.": "افصل بين قيم المحور Y باستخدام الفواصل.",
+ "Write image to a directory (default - log/images) and generation parameters into csv file.": "اكتب الصورة إلى مجلد (الافتراضي - log/images) وتوليد المتغيرات في ملف csv.",
+ "Open images output directory": "افتح مجلد مخرجات الصور",
+ "How much to blur the mask before processing, in pixels.": "كم يتم تضبيب القناع قبل المعالجة ، بالبكسل.",
+ "What to put inside the masked area before processing it with Stable Diffusion.": "ما يجب وضعه داخل المنطقة المقنعة قبل معالجتها باستخدام الانتشار المستقر.",
+ "fill it with colors of the image": "املأها بألوان الصورة",
+ "keep whatever was there originally": "احتفظ بكل ما كان هناك في الأصل",
+ "fill it with latent space noise": "املأه بضوضاء الفضاء الكامنة",
+ "fill it with latent space zeroes": "املأه بأصفار الفضاء الكامنة",
+ "Upscale masked region to target resolution, do inpainting, downscale back and paste into original image": "قم بترقية المنطقة المقنعة إلى الدقة المستهدفة و الرسم الجزئي ثم تقليص الحجم واللصق في الصورة الأصلية",
+ "Resize image to target resolution. Unless height and width match, you will get incorrect aspect ratio.": "تغيير حجم الصورة إلى الدقة المستهدفة. ما لم يتطابق الطول والعرض ، ستحصل على نسبة عرض إلى ارتفاع غير صحيحة.",
+ "Resize the image so that entirety of target resolution is filled with the image. Crop parts that stick out.": "قم بتغيير حجم الصورة بحيث يتم ملء الدقة المستهدفة بالكامل بالصورة. يتم قطع المناطق التي تبرز.",
+ "Resize the image so that entirety of image is inside target resolution. Fill empty space with image's colors.": "قم بتغيير حجم الصورة بحيث تكون الصورة بأكملها داخل الدقة المستهدفة. املأ المساحة الفارغة بألوان الصورة.",
+ "How many times to repeat processing an image and using it as input for the next iteration": "كم مرة يتم تكرار معالجة صورة واستخدامها كمدخل للتكرار التالي",
+ "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.": "في وضع حلقة الاسترجاع ، يتم ضرب قوة تقليل الضوضاء بهذه القيمة في كل حلقة. يعني <1 تقليل التنوع بحيث يتقارب التسلسل الخاص بك على صورة ثابتة. > 1 يعني زيادة التنوع بحيث يصبح تسلسلك أكثر وأكثر فوضوية.",
+ "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.": "الترقية باستخدام الانتشار المستقر ، كم يجب أن يكون مقدار التداخل بالبكسل بين المربعات. تتداخل المربعات بحيث لا يكون هناك خط واضح للعيان عند دمجها مرة أخرى في صورة واحدة.",
+ "A directory on the same machine where the server is running.": "مجلد على نفس الجهاز حيث يتم تشغيل الخادم.",
+ "Leave blank to save images to the default path.": "اتركه فارغًا لحفظ الصور في المسار الافتراضي.",
+ "Result = A * (1 - M) + B * M": "النتيجة = A * (1 - M) + B * M",
+ "Result = A + (B - C) * M": "النتيجة = A + (B - C) * M",
+ "1st and last digit must be 1. ex:'1, 2, 1'": "يجب أن يكون الرقم الأول والأخير 1. على سبيل المثال: '1 ، 2 ، 1'",
+ "Path to directory with input images": "المسار إلى مجلد الصور المدخلة",
+ "Path to directory where to write outputs": "المسار إلى مجلد كتابة النتائج",
+ "Input images directory": "مجلد الصور المدخلة",
+ "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], [prompt_words], [date], [datetime], [datetime<Format>], [datetime<Format><Time Zone>], [job_timestamp]; leave empty for default.": "استخدم العلامات التالية لتعريف كيفية اختيار أسماء الملفات للصور: [steps], [cfg], [prompt], [prompt_no_styles], [prompt_spaces], [width], [height], [styles], [sampler], [seed], [model_hash], [prompt_words], [date], [datetime], [datetime<Format>], [datetime<Format><Time Zone>], [job_timestamp] ؛ اتركه فارغا للوضع الافتراضي.",
+ "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.": "إذا تم تمكين هذا الخيار ، فلن تتم إضافة العلامة المائية إلى الصور التي تم إنشاؤها. تحذير: إذا لم تقم بإضافة علامة مائية ، فقد تكون تتصرف بطريقة غير أخلاقية.",
+ "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], [prompt_words], [date], [datetime], [datetime<Format>], [datetime<Format><Time Zone>], [job_timestamp]; leave empty for default.": "استخدم العلامات التالية لتحديد كيفية اختيار المجادت الفرعية للصور و الإطارات الشبكية : [steps], [cfg], [prompt], [prompt_no_styles], [prompt_spaces], [width], [height], [styles], [sampler], [seed], [model_hash], [prompt_words], [date], [datetime], [datetime<Format>], [datetime<Format><Time Zone>], [job_timestamp] ؛ اتركه فارغا للوضع الافتراضي.",
+ "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.": "سيتم استخدام هذا التعبير العادي لاستخراج الكلمات من اسم الملف ، وسيتم ضمها باستخدام الخيار أدناه في نص التسمية المستخدم للتدريب. اتركه فارغًا للاحتفاظ بنص اسم الملف كما هو.",
+ "This string will be used to join split words into a single line if the option above is enabled.": "سيتم استخدام هذا النص لضم الكلمات المقسمة إلى سطر واحد إذا تم تمكين الخيار أعلاه.",
+ "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.": "قائمة أسماء الإعدادات ، مفصولة بفواصل ، للإعدادات التي يجب أن تنتقل إلى شريط الوصول السريع في الأعلى ، بدلاً من علامة تبويب الإعداد المعتادة. انظر modules / shared.py للتعرف على أسماء الإعدادات. يتطلب إعادة التشغيل للتطبيق.",
+ "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.": "إذا كانت هذه القيم غير صفرية ، فستتم إضافتها إلى البذرة واستخدامها لتهيئة فوضى الضوضاء عند استخدام أنظمة أخذ العينات باستخدام الوقت المتبقي. يمكنك استخدام ذلك لإنتاج المزيد من التنوعات في الصور ، أو يمكنك استخدامه لمطابقة صور البرامج الأخرى إذا كنت تعرف ما تفعله."
+} \ No newline at end of file
diff --git a/localizations/es_ES.json b/localizations/es_ES.json
new file mode 100644
index 00000000..d9ca4ef7
--- /dev/null
+++ b/localizations/es_ES.json
@@ -0,0 +1,418 @@
+{
+ "⤡": "⤡",
+ "⊞": "⊞",
+ "×": "×",
+ "❮": "❮",
+ "❯": "❯",
+ "Loading...": "Cargando...",
+ "view": "mostrar",
+ "api": "api",
+ "•": "•",
+ "built with gradio": "Construido con Gradio",
+ "Stable Diffusion checkpoint": "Stable Diffusion checkpoint",
+ "txt2img": "txt2img",
+ "img2img": "img2img",
+ "Extras": "Extras",
+ "PNG Info": "PNG Info",
+ "Checkpoint Merger": "Checkpoint Merger",
+ "Train": "Train",
+ "Settings": "Ajustes",
+ "Prompt": "Prompt",
+ "Negative prompt": "Prompt negativo",
+ "Run": "Ejecutar",
+ "Skip": "Saltar",
+ "Interrupt": "Interrumpir",
+ "Generate": "Generar",
+ "Style 1": "Estilo 1",
+ "Style 2": "Estilo 2",
+ "Label": "Etiqueta",
+ "File": "Archivo",
+ "Drop File Here": "Suelta el Archivo Aquí",
+ "-": "-",
+ "o": "o",
+ "Click to Upload": "Click para Cargar",
+ "Image": "Imagen",
+ "Check progress": "Comprobar progreso",
+ "Check progress (first)": "Comprobar progreso (inicial)",
+ "Sampling Steps": "Sampling Steps",
+ "Sampling method": "Sampling method",
+ "Euler a": "Euler a",
+ "Euler": "Euler",
+ "LMS": "LMS",
+ "Heun": "Heun",
+ "DPM2": "DPM2",
+ "DPM2 a": "DPM2 a",
+ "DPM fast": "DPM fast",
+ "DPM adaptive": "DPM adaptive",
+ "LMS Karras": "LMS Karras",
+ "DPM2 Karras": "DPM2 Karras",
+ "DPM2 a Karras": "DPM2 a Karras",
+ "DDIM": "DDIM",
+ "PLMS": "PLMS",
+ "Width": "Ancho",
+ "Height": "Alto",
+ "Restore faces": "Restaurar rostros",
+ "Tiling": "Mosaico",
+ "Highres. fix": "Highres. fix",
+ "Firstpass width": "Ancho original",
+ "Firstpass height": "Alto original",
+ "Denoising strength": "Denoising strength",
+ "Batch count": "Batch count",
+ "Batch size": "Batch size",
+ "CFG Scale": "CFG Scale",
+ "Seed": "Seed",
+ "Extra": "Extra",
+ "Variation seed": "Variation seed",
+ "Variation strength": "Variation strength",
+ "Resize seed from width": "Redimensionar seed del ancho",
+ "Resize seed from height": "Redimensionar seed del alto",
+ "Script": "Script",
+ "None": "Ninguno",
+ "Prompt matrix": "Prompt matrix",
+ "Prompts from file or textbox": "Prompts desde archivo o campo de texto",
+ "X/Y plot": "X/Y plot",
+ "Put variable parts at start of prompt": "Poner partes variables al inicio del prompt",
+ "Show Textbox": "Mostrar Campo de texto",
+ "File with inputs": "Archivo con inputs",
+ "Prompts": "Prompts",
+ "X type": "X type",
+ "Nothing": "Nada",
+ "Var. seed": "Var. seed",
+ "Var. strength": "Var. strength",
+ "Steps": "Steps",
+ "Prompt S/R": "Prompt S/R",
+ "Prompt order": "Prompt order",
+ "Sampler": "Sampler",
+ "Checkpoint name": "Checkpoint name",
+ "Hypernetwork": "Hypernetwork",
+ "Hypernet str.": "Hypernet str.",
+ "Sigma Churn": "Sigma Churn",
+ "Sigma min": "Sigma min",
+ "Sigma max": "Sigma max",
+ "Sigma noise": "Sigma noise",
+ "Eta": "Eta",
+ "Clip skip": "Clip skip",
+ "Denoising": "Denoising",
+ "X values": "X values",
+ "Y type": "Y type",
+ "Y values": "Y values",
+ "Draw legend": "Agregar leyenda",
+ "Include Separate Images": "Incluir Imágenes Separadas",
+ "Keep -1 for seeds": "Mantener -1 para seeds",
+ "Drop Image Here": "Suelta la Imagen Aquí",
+ "Save": "Guardar",
+ "Send to img2img": "Enviar a img2img",
+ "Send to inpaint": "Enviar a inpaint",
+ "Send to extras": "Enviar a extras",
+ "Make Zip when Save?": "Crear Zip al Guardar?",
+ "Textbox": "Campo de texto",
+ "Interrogate\nCLIP": "Interrogar\nCLIP",
+ "Inpaint": "Inpaint",
+ "Batch img2img": "Batch img2img",
+ "Image for img2img": "Imagen para img2img",
+ "Image for inpainting with mask": "Imagen para inpainting con mask",
+ "Mask": "Mask",
+ "Mask blur": "Mask blur",
+ "Mask mode": "Mask mode",
+ "Draw mask": "Dibujar mask",
+ "Upload mask": "Cargar mask",
+ "Masking mode": "Masking mode",
+ "Inpaint masked": "Inpaint masked",
+ "Inpaint not masked": "Inpaint not masked",
+ "Masked content": "Masked content",
+ "fill": "fill",
+ "original": "original",
+ "latent noise": "latent noise",
+ "latent nothing": "latent nothing",
+ "Inpaint at full resolution": "Inpaint a resolución completa",
+ "Inpaint at full resolution padding, pixels": "Inpaint a resolución completa padding, pixeles",
+ "Process images in a directory on the same machine where the server is running.": "Procesa imágenes en un directorio en la misma máquina donde se ejecuta el servidor.",
+ "Use an empty output directory to save pictures normally instead of writing to the output directory.": "Usa un directorio de salida vacío para guardar imágenes normalmente en lugar de escribir en el directorio de salida.",
+ "Input directory": "Directorio de entrada",
+ "Output directory": "Directorio de salida",
+ "Resize mode": "Modo de cambio de tamaño",
+ "Just resize": "Solo redimensionar",
+ "Crop and resize": "Recortar y redimensionar",
+ "Resize and fill": "Redimensionar y rellenar",
+ "img2img alternative test": "img2img alternative test",
+ "Loopback": "Loopback",
+ "Outpainting mk2": "Outpainting mk2",
+ "Poor man's outpainting": "Poor man's outpainting",
+ "SD upscale": "SD upscale",
+ "should be 2 or lower.": "debe ser 2 o menos.",
+ "Override `Sampling method` to Euler?(this method is built for it)": "Anular `Sampling method` a Euler? (este método está diseñado para ello)",
+ "Override `prompt` to the same value as `original prompt`?(and `negative prompt`)": "Anular `prompt` al mismo valor `prompt original`? (y `prompt negativo`)",
+ "Original prompt": "Prompt original",
+ "Original negative prompt": "Promp negativo original",
+ "Override `Sampling Steps` to the same value as `Decode steps`?": "Anular `Sampling Steps` al mismo valor de `Decode steps`?",
+ "Decode steps": "Decode steps",
+ "Override `Denoising strength` to 1?": "Anular `Denoising strength` a 1?",
+ "Decode CFG scale": "Decode CFG scale",
+ "Randomness": "Aleatoriedad",
+ "Sigma adjustment for finding noise for image": "Ajuste Sigma para encontrar ruido para la imagen.",
+ "Loops": "Loops",
+ "Denoising strength change factor": "Denoising strength change factor",
+ "Recommended settings: Sampling Steps: 80-100, Sampler: Euler a, Denoising strength: 0.8": "Ajustes recomendados: Sampling Steps: 80-100, Sampler: Euler a, Denoising strength: 0.8",
+ "Pixels to expand": "Píxeles para expandir",
+ "Outpainting direction": "Dirección Outpainting",
+ "left": "izquierda",
+ "right": "derecha",
+ "up": "arriba",
+ "down": "abajo",
+ "Fall-off exponent (lower=higher detail)": "Fall-off exponent (inferior=mayor detalle)",
+ "Color variation": "Variación de color",
+ "Will upscale the image to twice the dimensions; use width and height sliders to set tile size": "Mejorará la imagen al doble de las dimensiones; usa los controles deslizantes de ancho y alto para establecer el tamaño del mosaico",
+ "Tile overlap": "Solapar mosaicos",
+ "Upscaler": "Upscaler",
+ "Lanczos": "Lanczos",
+ "LDSR": "LDSR",
+ "SwinIR 4x": "SwinIR 4x",
+ "ScuNET GAN": "ScuNET GAN",
+ "ScuNET PSNR": "ScuNET PSNR",
+ "ESRGAN_4x": "ESRGAN_4x",
+ "Single Image": "Imagen Única",
+ "Batch Process": "Batch Process",
+ "Batch from Directory": "Batch desde Directorio",
+ "Source": "Origen",
+ "Show result images": "Mostrar resultados de imágenes",
+ "Scale by": "Escalar por",
+ "Scale to": "Escalar a",
+ "Resize": "Redimensionar",
+ "Crop to fit": "Recortar para ajustar",
+ "Upscaler 2 visibility": "Upscaler 2 visibilidad",
+ "GFPGAN visibility": "GFPGAN visibilidad",
+ "CodeFormer visibility": "CodeFormer visibilidad",
+ "CodeFormer weight (0 = maximum effect, 1 = minimum effect)": "CodeFormer peso (0 = efecto máximo, 1 = efecto mínimo)",
+ "Open output directory": "Abrir directorio de salida",
+ "Send to txt2img": "Enviar a txt2img",
+ "A merger of the two checkpoints will be generated in your": "Se generará una fusión de los dos checkpoints en su",
+ "checkpoint": "checkpoint",
+ "directory.": "directorio.",
+ "Primary model (A)": "Modelo primario (A)",
+ "Secondary model (B)": "Modelo secundario (B)",
+ "Tertiary model (C)": "Modelo terciario (C)",
+ "Custom Name (Optional)": "Nombre personalizado (Opcional)",
+ "Multiplier (M) - set to 0 to get model A": "Multiplier (M) - establecer en 0 para obtener el modelo A",
+ "Interpolation Method": "Método de interpolación",
+ "Weighted sum": "Weighted sum",
+ "Add difference": "Add difference",
+ "Save as float16": "Guardar como float16",
+ "See": "Ver ",
+ "wiki": "wiki ",
+ "for detailed explanation.": "para una explicación detallada.",
+ "Create embedding": "Crear embedding",
+ "Create hypernetwork": "Crear hypernetwork",
+ "Preprocess images": "Preprocesar imágenes",
+ "Name": "Nombre",
+ "Initialization text": "Texto de inicialización",
+ "Number of vectors per token": "Número de vectores por token",
+ "Overwrite Old Embedding": "Sobrescribir Embedding Anterior",
+ "Modules": "Módulos",
+ "Enter hypernetwork layer structure": "Ingresa la estructura de capa del hypernetwork",
+ "Select activation function of hypernetwork": "Selecciona la función de activación del hypernetwork",
+ "linear": "linear",
+ "relu": "relu",
+ "leakyrelu": "leakyrelu",
+ "elu": "elu",
+ "swish": "swish",
+ "Add layer normalization": "Agregar normalización de capa",
+ "Use dropout": "Usar dropout",
+ "Overwrite Old Hypernetwork": "Sobrescribir Hypernetwork Anterior",
+ "Source directory": "Directorio de origen",
+ "Destination directory": "Directorio de salida",
+ "Existing Caption txt Action": "Existing Caption txt Action",
+ "ignore": "ignorar",
+ "copy": "copiar",
+ "prepend": "anteponer",
+ "append": "añadir",
+ "Create flipped copies": "Crear copias volteadas",
+ "Split oversized images": "Dividir imágenes grandes",
+ "Use BLIP for caption": "Usar BLIP para subtítulo",
+ "Use deepbooru for caption": "Usar deepbooru para subtítulo",
+ "Split image threshold": "Threshold imagen dividida",
+ "Split image overlap ratio": "Overlap ratio imagen dividida",
+ "Preprocess": "Preproceso",
+ "Train an embedding or Hypernetwork; you must specify a directory with a set of 1:1 ratio images": "Entrenar un embedding o Hypernetwork; debes especificar un directorio con un conjunto de imágenes con una proporción de 1:1 ",
+ "[wiki]": "[wiki]",
+ "Embedding": "Embedding",
+ "Embedding Learning rate": "Embedding Learning rate",
+ "Hypernetwork Learning rate": "Hypernetwork Learning rate",
+ "Dataset directory": "Directorio dataset",
+ "Log directory": "Directorio log",
+ "Prompt template file": "Prompt archivos plantilla",
+ "Max steps": "Max steps",
+ "Save an image to log directory every N steps, 0 to disable": "Guarda una imagen en el directorio log cada N pasos, 0 para deshabilitar",
+ "Save a copy of embedding to log directory every N steps, 0 to disable": "Guarda una copia de embedding en el directorio log cada N pasos, 0 para deshabilitar",
+ "Save images with embedding in PNG chunks": "Guarda imágenes con embedding en fragmentos PNG",
+ "Read parameters (prompt, etc...) from txt2img tab when making previews": "Leer parámetros (prompt, etc...) desde la pestaña txt2img al hacer vistas previas",
+ "Train Hypernetwork": "Train Hypernetwork",
+ "Train Embedding": "Train Embedding",
+ "Apply settings": "Aplicar ajustes",
+ "Saving images/grids": "Guardar imágenes/grids",
+ "Always save all generated images": "Siempre guardar imágenes generadas",
+ "File format for images": "Formato de archivo para imágenes",
+ "Images filename pattern": "Patrón nombre archivo imágenes",
+ "Add number to filename when saving": "Agregar número al nombre de archivo al guardar",
+ "Always save all generated image grids": "Siempre guardar grids de imágenes generadas",
+ "File format for grids": "Formato de archivo para grids",
+ "Add extended info (seed, prompt) to filename when saving grid": "Agregar información extendida (seed, prompt) al nombre del archivo al guardar grid",
+ "Do not save grids consisting of one picture": "No guardar grids que consisten en una imagen",
+ "Prevent empty spots in grid (when set to autodetect)": "Evitar espacios vacíos en grids (cuando se establece detección automática)",
+ "Grid row count; use -1 for autodetect and 0 for it to be same as batch size": "Recuento de filas de grids; usar -1 para la detección automática y 0 para que sea igual al batch size",
+ "Save text information about generation parameters as chunks to png files": "Guardar información de texto sobre parámetros de generación como fragmentos en archivos png",
+ "Create a text file next to every image with generation parameters.": "Crear un archivo de texto junto a cada imagen con parámetros de generación.",
+ "Save a copy of image before doing face restoration.": "Guardar una copia de la imagen antes de restaurar rostro.",
+ "Quality for saved jpeg images": "Calidad para imágenes jpeg guardadas",
+ "If PNG image is larger than 4MB or any dimension is larger than 4000, downscale and save copy as JPG": "Si la imagen PNG es más grande de 4 MB o cualquier dimensión es más grande que 4000, reduce la escala y guarda la copia como JPG",
+ "Use original name for output filename during batch process in extras tab": "Use el nombre original para el nombre del archivo de salida durante el batch process en la pestaña extras",
+ "When using 'Save' button, only save a single selected image": "Al usar el botón 'Guardar', solo guarda una sola imagen seleccionada",
+ "Do not add watermark to images": "No agregar watermark a las imágenes",
+ "Paths for saving": "Directorios para guardar",
+ "Output directory for images; if empty, defaults to three directories below": "Directorio de imágenes; si está vacío, se utilizan los siguientes 3 directorios",
+ "Output directory for txt2img images": "Directorio para guardar imágenes de txt2img",
+ "Output directory for img2img images": "Directorio para guardar imágenes de img2img",
+ "Output directory for images from extras tab": "Directorio para guardar imágenes de extras",
+ "Output directory for grids; if empty, defaults to two directories below": "Directorio de grids; si está vacío, se utilizan los siguientes 2 directorios",
+ "Output directory for txt2img grids": "Directorio para guardar txt2img grids",
+ "Output directory for img2img grids": "Directorio para guardar img2img grids",
+ "Directory for saving images using the Save button": "Directorio para guardar imágenes usando el botón Guardar",
+ "Saving to a directory": "Guardando a un directorio",
+ "Save images to a subdirectory": "Guardar imágenes a un subdirectorio",
+ "Save grids to a subdirectory": "Guardar grids a un subdirectorio",
+ "When using \"Save\" button, save images to a subdirectory": "Al usar el botón \"Guardar\", guarda las imágenes en un subdirectorio",
+ "Directory name pattern": "Patrón nombre directorio",
+ "Max prompt words for [prompt_words] pattern": "Máximo de palabras en prompt [prompt_words] para patrón",
+ "Upscaling": "Upscaling",
+ "Tile size for ESRGAN upscalers. 0 = no tiling.": "Tamaño mosaico para ESRGAN upscalers. 0 = sin mosaico.",
+ "Tile overlap, in pixels for ESRGAN upscalers. Low values = visible seam.": "Solapar mosaico, en pixeles para ESRGAN upscalers. Valores bajos = unión visible.",
+ "Tile size for all SwinIR.": "Tamaño mosaico para SwinIR.",
+ "Tile overlap, in pixels for SwinIR. Low values = visible seam.": "Solapar mosaico, en pixeles para SwinIR. Valores bajos = unión visible.",
+ "LDSR processing steps. Lower = faster": "LDSR processing steps. Más bajo = rápido",
+ "Upscaler for img2img": "Upscaler para img2img",
+ "Upscale latent space image when doing hires. fix": "Upscale latent space al aplicar hires. fix",
+ "Face restoration": "Restauración de rostro",
+ "CodeFormer weight parameter; 0 = maximum effect; 1 = minimum effect": "CodeFormer parámetro peso; 0 = máximo efecto; 1 = mínimo efecto",
+ "Move face restoration model from VRAM into RAM after processing": "Mover modelo de restauración de rostro del VRAM al RAM después de procesar",
+ "System": "Sistema",
+ "VRAM usage polls per second during generation. Set to 0 to disable.": "Sondeos de uso de VRAM por segundo durante la generación. Establecer en 0 para deshabilitar.",
+ "Always print all generation info to standard output": "Imprime siempre toda la información de generación en la salida estándar",
+ "Add a second progress bar to the console that shows progress for an entire job.": "Agrega una segunda barra de progreso a la consola que muestra el progreso de un trabajo completo.",
+ "Training": "Entrenamiento",
+ "Move VAE and CLIP to RAM when training hypernetwork. Saves VRAM.": "Mover VAE y CLIP al RAM al entrenar un hypernetwork. Ahorra VRAM.",
+ "Filename word regex": "Filename word regex",
+ "Filename join string": "Filename join string",
+ "Number of repeats for a single input image per epoch; used only for displaying epoch number": "Número de repeticiones para una sola imagen de entrada por epoch; utilizado solo para mostrar el número epoch",
+ "Save an csv containing the loss to log directory every N steps, 0 to disable": "Guarda un csv que contenga la pérdida en el directorio log cada N pasos, 0 para deshabilitar",
+ "Stable Diffusion": "Stable Diffusion",
+ "Checkpoints to cache in RAM": "Checkpoints al cache en RAM",
+ "Hypernetwork strength": "Hypernetwork strength",
+ "Apply color correction to img2img results to match original colors.": "Aplica la corrección de color a los resultados de img2img para que coincidan con los colores originales.",
+ "Save a copy of image before applying color correction to img2img results": "Guarda una copia de la imagen antes de aplicar la corrección de color a los resultados de img2img",
+ "With img2img, do exactly the amount of steps the slider specifies (normally you'd do less with less denoising).": "Con img2img, hace exactamente la cantidad de pasos que especifica el slider (normalmente haría menos con menos eliminación de ruido).",
+ "Enable quantization in K samplers for sharper and cleaner results. This may change existing seeds. Requires restart to apply.": "Habilita la cuantificación en K samplers para obtener resultados más nítidos y limpios. Esto puede cambiar los seeds existentes. Requiere reiniciar para aplicar.",
+ "Emphasis: use (text) to make model pay more attention to text and [text] to make it pay less attention": "Énfasis: utiliza (texto) para que el modelo preste más atención al texto y [texto] para que preste menos atención",
+ "Use old emphasis implementation. Can be useful to reproduce old seeds.": "Utiliza la implementación de énfasis antiguo. Puede ser útil para reproducir seeds anteriores.",
+ "Make K-diffusion samplers produce same images in a batch as when making a single image": "Hace que los K-diffusion samplers produzcan las mismas imágenes en un lote que cuando se crea una sola imagen",
+ "Increase coherency by padding from the last comma within n tokens when using more than 75 tokens": "Aumenta la coherencia rellenando desde la última coma dentro de n tokens cuando se use más de 75 tokens",
+ "Filter NSFW content": "Filtrar contenido NSFW",
+ "Stop At last layers of CLIP model": "Detener en las últimas capas del modelo CLIP",
+ "Interrogate Options": "Opciones de Interrogar",
+ "Interrogate: keep models in VRAM": "Interrogar: mantener modelos en VRAM",
+ "Interrogate: use artists from artists.csv": "Interrogar: utilizar artistas de artists.csv",
+ "Interrogate: include ranks of model tags matches in results (Has no effect on caption-based interrogators).": "Interrogar: incluir rangos de coincidencias de etiquetas de modelos en los resultados (No tiene efecto en los interrogadores basados en subtítulos).",
+ "Interrogate: num_beams for BLIP": "Interrogar: num_beams para BLIP",
+ "Interrogate: minimum description length (excluding artists, etc..)": "Interrogar: longitud mínima de la descripción (excluyendo artistas, etc.)",
+ "Interrogate: maximum description length": "Interrogar: longitud máxima de la descripción",
+ "CLIP: maximum number of lines in text file (0 = No limit)": "CLIP: número máximo de líneas en el archivo de texto (0 = Sin límite)",
+ "Interrogate: deepbooru score threshold": "Interrogar: deepbooru score threshold",
+ "Interrogate: deepbooru sort alphabetically": "Interrogar: deepbooru ordenar alfabéticamente",
+ "use spaces for tags in deepbooru": "usar espacios para etiquetas en deepbooru",
+ "escape (\\) brackets in deepbooru (so they are used as literal brackets and not for emphasis)": "corchetes de escape (\\) en deepbooru (por lo que se usan como corchetes literales y no para enfatizar)",
+ "User interface": "Interfaz de usuario",
+ "Show progressbar": "Mostrar barra de progreso",
+ "Show image creation progress every N sampling steps. Set 0 to disable.": "Muestra el progreso de creación de la imagen cada N sampling steps. Establecer 0 para deshabilitar.",
+ "Show previews of all images generated in a batch as a grid": "Mostrar vistas previas de todas las imágenes generadas en un batch como un grid",
+ "Show grid in results for web": "Mostrar grids en resultados para web",
+ "Do not show any images in results for web": "No mostrar ninguna imagen en los resultados para web",
+ "Add model hash to generation information": "Agregar hash de modelo a la información de generación",
+ "Add model name to generation information": "Agregar nombre de modelo a la información de generación",
+ "When reading generation parameters from text into UI (from PNG info or pasted text), do not change the selected model/checkpoint.": "Al leer los parámetros de generación del texto en la interfaz de usuario (desde PNG Info o texto pegado), no cambia el modelo/checkpoint seleccionado.",
+ "Font for image grids that have text": "Tipografía para grids de imágenes que tienen texto",
+ "Enable full page image viewer": "Habilitar visor de imágenes de página completa",
+ "Show images zoomed in by default in full page image viewer": "Mostrar imágenes ampliadas de forma predeterminada en el visor de imágenes de página completa",
+ "Show generation progress in window title.": "Muestra el progreso de la generación en el título de la ventana del navegador.",
+ "Quicksettings list": "Lista de ajustes rápidos",
+ "Localization (requires restart)": "Traducción (requiere reiniciar)",
+ "Sampler parameters": "Parámetros sampler",
+ "Hide samplers in user interface (requires restart)": "Ocultar samplers en interfaz de usuario (requiere reiniciar)",
+ "eta (noise multiplier) for DDIM": "eta (noise multiplier) para DDIM",
+ "eta (noise multiplier) for ancestral samplers": "eta (noise multiplier) para ancestral samplers",
+ "img2img DDIM discretize": "img2img DDIM discretize",
+ "uniform": "uniform",
+ "quad": "quad",
+ "sigma churn": "sigma churn",
+ "sigma tmin": "sigma tmin",
+ "sigma noise": "sigma noise",
+ "Eta noise seed delta": "Eta noise seed delta",
+ "Request browser notifications": "Solicitar notificaciones del navegador",
+ "Download localization template": "Descargar plantilla de traducción",
+ "Reload custom script bodies (No ui updates, No restart)": "Recargar custom script bodies (Sin actualizar UI, Sin reiniciar)",
+ "Restart Gradio and Refresh components (Custom Scripts, ui.py, js and css only)": "Reiniciar Gradio y Refrescar componentes (Custom Scripts, ui.py, js y css)",
+ "Prompt (press Ctrl+Enter or Alt+Enter to generate)": "Prompt (presiona Ctrl+Enter o Alt+Enter para generar)",
+ "Negative prompt (press Ctrl+Enter or Alt+Enter to generate)": "Prompt negativo (presiona Ctrl+Enter o Alt+Enter para generar)",
+ "Add a random artist to the prompt.": "Agregar un artista aleatorio al prompt.",
+ "Read generation parameters from prompt or last generation if prompt is empty into user interface.": "Leer los parámetros de generación del prompt o de la última generación si el prompt está vacío en la interfaz de usuario.",
+ "Save style": "Guardar estilo",
+ "Apply selected styles to current prompt": "Aplicar estilos seleccionados al prompt",
+ "Stop processing current image and continue processing.": "Dejar de procesar la imagen actual y continuar procesando.",
+ "Stop processing images and return any results accumulated so far.": "Dejar de procesar imágenes y devuelva los resultados acumulados hasta el momento.",
+ "Style to apply; styles have components for both positive and negative prompts and apply to both": "Estilo a aplicar; los estilos tienen componentes tanto para prompts positivos como negativos y se aplican a ambos",
+ "Do not do anything special": "No hacer nada especial",
+ "Which algorithm to use to produce the image": "Qué algoritmo usar para producir la imagen",
+ "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": "Euler Ancestral - muy creativo, cada uno puede obtener una imagen completamente diferente dependiendo del conteo de steps, configurar los steps a más de 30-40 no ayuda",
+ "Denoising Diffusion Implicit Models - best at inpainting": "Denoising Diffusion Implicit Models - funcionan mejor para inpainting",
+ "Produce an image that can be tiled.": "Produce una imagen que puede usarse como mosaico.",
+ "Use a two step process to partially create an image at smaller resolution, upscale, and then improve details in it without changing composition": "Usa un proceso de dos pasos para crear parcialmente una imagen con una resolución más pequeña, mejora la escala y luego mejora los detalles sin cambiar la composición",
+ "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.": "Determina qué tan poco respeto debe tener el algoritmo por el contenido de la imagen. En 0, nada cambiará y en 1 obtendrá una imagen no relacionada. Con valores por debajo de 1.0, el procesamiento tomará menos steps de los que especifica el slider de Sampling Steps.",
+ "How many batches of images to create": "Cuantos batches de imágenes para crear",
+ "How many image to create in a single batch": "Cuantas imágenes para crear en un solo batch",
+ "Classifier Free Guidance Scale - how strongly the image should conform to prompt - lower values produce more creative results": "Classifier Free Guidance Scale - con qué fuerza debe ajustarse la imagen al prompt: los valores más bajos producen resultados más creativos",
+ "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": "Un valor que determina la salida del generador de números aleatorios: si creas una imagen con los mismos parámetros y el seed que otra imagen, obtendrás el mismo resultado",
+ "Set seed to -1, which will cause a new random number to be used every time": "Establece el seed a -1, lo que hará que se use un nuevo número aleatorio cada vez",
+ "Reuse seed from last generation, mostly useful if it was randomed": "Reutilice el seed de la última generación, muy útil si fue aleatoria",
+ "Seed of a different picture to be mixed into the generation.": "Seed de una imagen diferente para ser mezclada en la generación.",
+ "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).": "Qué fuerte de una variación para producir. En 0, no habrá ningún efecto. En 1, obtendrá la imagen completa con variation seed (excepto para ancestral samplers, donde solo obtendrás algo).",
+ "Make an attempt to produce a picture similar to what would have been produced with same seed at specified resolution": "Intenta producir una imagen similar a la que se habría producido con el mismo seed a la resolución especificada",
+ "Separate values for X axis using commas.": "Separar valores para X usando comas.",
+ "Separate values for Y axis using commas.": "Separar valores para Y usando comas.",
+ "Write image to a directory (default - log/images) and generation parameters into csv file.": "Escribe la imagen en un directorio (predeterminado: log/images) y los parámetros de generación en el archivo csv.",
+ "Open images output directory": "Abrir directorio de imágenes",
+ "How much to blur the mask before processing, in pixels.": "Cuánto blur al mask antes de procesar, en píxeles.",
+ "What to put inside the masked area before processing it with Stable Diffusion.": "Qué poner dentro del área con mask antes de procesarlo con Stable Diffusion.",
+ "fill it with colors of the image": "rellenarlo con los colores de la imagen",
+ "keep whatever was there originally": "mantener lo que estaba allí originalmente",
+ "fill it with latent space noise": "rellenarlo con latent space noise",
+ "fill it with latent space zeroes": "rellenarlo con latent space zeroes",
+ "Upscale masked region to target resolution, do inpainting, downscale back and paste into original image": "Upscale la región con mask a la resolución objetivo, vuelve a pintar, reduce la escala hacia atrás y pégala en la imagen original",
+ "Resize image to target resolution. Unless height and width match, you will get incorrect aspect ratio.": "Cambia el tamaño de la imagen a la resolución destino. A menos que la altura y el ancho coincidan, obtendrás una relación de aspecto incorrecta.",
+ "Resize the image so that entirety of target resolution is filled with the image. Crop parts that stick out.": "Cambia el tamaño de la imagen para que la totalidad de la resolución destino se llene con la imagen. Recorta las partes que sobresalen.",
+ "Resize the image so that entirety of image is inside target resolution. Fill empty space with image's colors.": "Cambia el tamaño de la imagen para que la totalidad de la imagen esté dentro de la resolución de destino. Rellena el espacio vacío con los colores de la imagen.",
+ "How many times to repeat processing an image and using it as input for the next iteration": "Cuántas veces repetir el procesamiento de una imagen y usarla como entrada para la próxima iteración",
+ "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.": "En modo loopback, en cada bucle, la fuerza de eliminación de ruido se multiplica por este valor. <1 significa variedad decreciente, por lo que su secuencia convergerá en una imagen fija. >1 significa aumentar la variedad, por lo que su secuencia se volverá cada vez más caótica.",
+ "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.": "Para SD upscale, cuánta superposición en píxeles debe haber entre mosaicos. Los mosaicos se superponen de modo que cuando se fusionan nuevamente en una imagen, no hay una unión claramente visible.",
+ "A directory on the same machine where the server is running.": "Un directorio en la misma máquina donde se ejecuta el servidor.",
+ "Leave blank to save images to the default path.": "Déjalo en blanco para guardar las imágenes en la ruta predeterminada.",
+ "Result = A * (1 - M) + B * M": "Resultado = A * (1 - M) + B * M",
+ "Result = A + (B - C) * M": "Resultado = A + (B - C) * M",
+ "1st and last digit must be 1. ex:'1, 2, 1'": "Primer y último dígito debe ser 1. ej:'1, 2, 1'",
+ "Path to directory with input images": "Ruta al directorio con imágenes de entrada",
+ "Path to directory where to write outputs": "Ruta al directorio donde escribir salidas",
+ "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], [prompt_words], [date], [datetime], [datetime<Format>], [datetime<Format><Time Zone>], [job_timestamp]; leave empty for default.": "Usa las siguientes etiquetas para definir cómo se eligen los nombres de archivo para las imágenes: [steps], [cfg], [prompt], [prompt_no_styles], [prompt_spaces], [width], [height], [styles], [sampler], [seed], [model_hash], [prompt_words], [date], [datetime], [datetime<Format>], [datetime<Format><Time Zone>], [job_timestamp]; dejar vacío para utilizar predeterminados.",
+ "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.": "Si esta opción está habilitada, el watermark no se agregará a las imágenes creadas. Advertencia: si no agregas un watermark, es posible que te estés comportando de manera poco ética.",
+ "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], [prompt_words], [date], [datetime], [datetime<Format>], [datetime<Format><Time Zone>], [job_timestamp]; leave empty for default.": "Usa las siguiente etiquetas para definir cómo los subdirectorios para imágenes y grids son seleccionados: [steps], [cfg], [prompt], [prompt_no_styles], [prompt_spaces], [width], [height], [styles], [sampler], [seed], [model_hash], [prompt_words], [date], [datetime], [datetime<Format>], [datetime<Format><Time Zone>], [job_timestamp]; dejar vacío para utilizar predeterminados.",
+ "Restore low quality faces using GFPGAN neural network": "Restaurar rostros de baja calidad utilizando GFPGAN neural network",
+ "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.": "Esta expresión regular se usará para extraer palabras del nombre de archivo y se unirán usando la opción a continuación en el texto de la etiqueta que se usa para el entrenamiento. Dejar vacío para mantener el texto del nombre de archivo tal como está.",
+ "This string will be used to join split words into a single line if the option above is enabled.": "Esta cadena se usará para unir palabras divididas en una sola línea si la opción anterior está habilitada.",
+ "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.": "Lista de nombres de configuración, separados por comas, para configuraciones que deben ir a la barra de acceso rápido en la parte superior, en lugar de la pestaña de configuración habitual. Ver modules/shared.py para configurar los nombres. Requiere reiniciar para aplicar.",
+ "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.": "Si este valor no es cero, se agregará al seed y se usará para inicializar RNG para ruidos cuando se usan samplers con Eta. Puedes usar esto para producir aún más variaciones de imágenes, o puedes usar esto para hacer coincidir imágenes de otro software si sabes lo que estás haciendo."
+}
diff --git a/localizations/ja_JP.json b/localizations/ja_JP.json
new file mode 100644
index 00000000..a6cc2477
--- /dev/null
+++ b/localizations/ja_JP.json
@@ -0,0 +1,482 @@
+{
+ "⤡": "⤡",
+ "⊞": "⊞",
+ "×": "×",
+ "❮": "❮",
+ "❯": "❯",
+ "Loading...": "読み込み中...",
+ "view": "view",
+ "api": "api",
+ "•": "•",
+ "gradioで作ろう": "gradioで作ろう",
+ "Stable Diffusion checkpoint": "Stable Diffusion checkpoint",
+ "Stop At last layers of CLIP model": "最後から何層目でCLIPを止めるか",
+ "txt2img": "txt2img",
+ "img2img": "img2img",
+ "Extras": "その他",
+ "PNG Info": "PNG内の情報を表示",
+ "Image Browser": "画像閲覧",
+ "Checkpoint Merger": "Checkpointの統合",
+ "Train": "学習",
+ "Create aesthetic embedding": "aesthetic embeddingを作る",
+ "Settings": "設定",
+ "Prompt": "プロンプト",
+ "Negative prompt": "ネガティブ プロンプト",
+ "Run": "実行",
+ "Skip": "スキップ",
+ "Interrupt": "中断",
+ "Generate": "生成!",
+ "Style 1": "スタイル 1",
+ "Style 2": "スタイル 2",
+ "Label": "ラベル",
+ "File": "ファイル",
+ "ここにファイルをドロップ": "ここにファイルをドロップ",
+ "-": "-",
+ "または": "または",
+ "クリックしてアップロード": "クリックしてアップロード",
+ "Image": "画像",
+ "Check progress": "Check progress",
+ "Check progress (first)": "Check progress (first)",
+ "Sampling Steps": "サンプリング回数",
+ "Sampling method": "サンプリングアルゴリズム",
+ "Euler a": "Euler a",
+ "Euler": "Euler",
+ "LMS": "LMS",
+ "Heun": "Heun",
+ "DPM2": "DPM2",
+ "DPM2 a": "DPM2 a",
+ "DPM fast": "DPM fast",
+ "DPM adaptive": "DPM adaptive",
+ "LMS Karras": "LMS Karras",
+ "DPM2 Karras": "DPM2 Karras",
+ "DPM2 a Karras": "DPM2 a Karras",
+ "DDIM": "DDIM",
+ "PLMS": "PLMS",
+ "Width": "幅",
+ "Height": "高さ",
+ "Restore faces": "顔修復",
+ "Tiling": "テクスチャ生成モード",
+ "Highres. fix": "高解像度 fix(マウスオーバーで詳細)",
+ "Firstpass width": "Firstpass width",
+ "Firstpass height": "Firstpass height",
+ "Denoising strength": "ノイズ除去強度",
+ "Batch count": "バッチ生成回数",
+ "Batch size": "バッチあたり生成枚数",
+ "CFG Scale": "CFG Scale",
+ "Seed": "シード値",
+ "Extra": "その他",
+ "Variation seed": "Variation シード値",
+ "Variation strength": "Variation 強度",
+ "Resize seed from width": "Resize seed from width",
+ "Resize seed from height": "Resize seed from height",
+ "Open for Clip Aesthetic!": "Open for Clip Aesthetic!",
+ "▼": "▼",
+ "Aesthetic weight": "Aesthetic weight",
+ "Aesthetic steps": "Aesthetic steps",
+ "Aesthetic learning rate": "Aesthetic learning rate",
+ "Slerp interpolation": "Slerp interpolation",
+ "Aesthetic imgs embedding": "Aesthetic imgs embedding",
+ "None": "なし",
+ "Aesthetic text for imgs": "Aesthetic text for imgs",
+ "Slerp angle": "Slerp angle",
+ "Is negative text": "Is negative text",
+ "Script": "スクリプト",
+ "Prompt matrix": "Prompt matrix",
+ "Prompts from file or textbox": "Prompts from file or textbox",
+ "Save steps of the sampling process to files": "Save steps of the sampling process to files",
+ "X/Y plot": "X/Y plot",
+ "Put variable parts at start of prompt": "Put variable parts at start of prompt",
+ "Show Textbox": "Show Textbox",
+ "File with inputs": "File with inputs",
+ "Prompts": "プロンプト",
+ "Save images to path": "Save images to path",
+ "X type": "X軸の種類",
+ "Nothing": "なし",
+ "Var. seed": "Var. seed",
+ "Var. strength": "Var. 強度",
+ "Steps": "ステップ数",
+ "Prompt S/R": "Prompt S/R",
+ "Prompt order": "Prompt order",
+ "Sampler": "サンプラー",
+ "Checkpoint name": "Checkpoint名",
+ "Hypernetwork": "Hypernetwork",
+ "Hypernet str.": "Hypernetの強度",
+ "Sigma Churn": "Sigma Churn",
+ "Sigma min": "Sigma min",
+ "Sigma max": "Sigma max",
+ "Sigma noise": "Sigma noise",
+ "Eta": "Eta",
+ "Clip skip": "Clip skip",
+ "Denoising": "Denoising",
+ "X values": "Xの値",
+ "Y type": "Y軸の種類",
+ "Y values": "Yの値",
+ "Draw legend": "凡例を描画",
+ "Include Separate Images": "Include Separate Images",
+ "Keep -1 for seeds": "シード値を-1で固定",
+ "ここに画像をドロップ": "ここに画像をドロップ",
+ "Save": "保存",
+ "Send to img2img": "img2imgに送る",
+ "Send to inpaint": "描き直しに送る",
+ "Send to extras": "その他タブに送る",
+ "Make Zip when Save?": "保存するときZipも同時に作る",
+ "Textbox": "Textbox",
+ "Interrogate\nCLIP": "Interrogate\nCLIP",
+ "Interrogate\nDeepBooru": "Interrogate\nDeepBooru",
+ "Inpaint": "描き直し(Inpaint)",
+ "Batch img2img": "Batch img2img",
+ "Image for img2img": "Image for img2img",
+ "Image for inpainting with mask": "Image for inpainting with mask",
+ "Mask": "マスク",
+ "Mask blur": "マスクぼかし",
+ "Mask mode": "マスクモード",
+ "Draw mask": "マスクをかける",
+ "Upload mask": "マスクをアップロードする",
+ "Masking mode": "マスキング方法",
+ "Inpaint masked": "マスクされた場所を描き直す",
+ "Inpaint not masked": "マスクされていない場所を描き直す",
+ "Masked content": "マスクされたコンテンツ",
+ "fill": "埋める",
+ "original": "オリジナル",
+ "latent noise": "潜在空間でのノイズ",
+ "latent nothing": "潜在空間での無",
+ "Inpaint at full resolution": "フル解像度で描き直す",
+ "Inpaint at full resolution padding, pixels": "フル解像度で描き直す際のパディング数。px単位。",
+ "Process images in a directory on the same machine where the server is running.": "サーバーが稼働しているマシンと同じフォルダにある画像を処理します",
+ "Use an empty output directory to save pictures normally instead of writing to the output directory.": "\"出力フォルダ\"を空にすると、通常の画像と同様に保存されます。",
+ "Input directory": "入力フォルダ",
+ "Output directory": "出力フォルダ",
+ "Resize mode": "リサイズモード",
+ "Just resize": "リサイズのみ",
+ "Crop and resize": "切り取ってからリサイズ",
+ "Resize and fill": "リサイズして埋める",
+ "img2img alternative test": "img2img alternative test",
+ "Loopback": "ループバック",
+ "Outpainting mk2": "Outpainting mk2",
+ "Poor man's outpainting": "Poor man's outpainting",
+ "SD upscale": "SD アップスケール",
+ "[C] Video to video": "[C] Video to video",
+ "should be 2 or lower.": "2以下にすること",
+ "Override `Sampling method` to Euler?(this method is built for it)": "サンプリングアルゴリズムをEulerに上書きする(そうすることを前提に設計されています)",
+ "Override `prompt` to the same value as `original prompt`?(and `negative prompt`)": "プロンプトをオリジナルプロンプトと同じ値に上書きする(ネガティブプロンプトも同様)",
+ "Original prompt": "オリジナルのプロンプト",
+ "Original negative prompt": "オリジナルのネガティブプロンプト",
+ "Override `Sampling Steps` to the same value as `Decode steps`?": "サンプリング数をデコードステップ数と同じ値に上書きする",
+ "Decode steps": "デコードステップ数",
+ "Override `Denoising strength` to 1?": "ノイズ除去強度を1に上書きする",
+ "Decode CFG scale": "Decode CFG scale",
+ "Randomness": "ランダム性",
+ "Sigma adjustment for finding noise for image": "Sigma adjustment for finding noise for image",
+ "Loops": "ループ数",
+ "Denoising strength change factor": "Denoising strength change factor",
+ "Recommended settings: Sampling Steps: 80-100, Sampler: Euler a, Denoising strength: 0.8": "推奨設定: サンプリング回数: 80-100, サンプリングアルゴリズム: Euler a, ノイズ除去強度: 0.8",
+ "Pixels to expand": "Pixels to expand",
+ "Outpainting direction": "Outpainting direction",
+ "left": "左",
+ "right": "右",
+ "up": "上",
+ "down": "下",
+ "Fall-off exponent (lower=higher detail)": "Fall-off exponent (lower=higher detail)",
+ "Color variation": "Color variation",
+ "Will upscale the image to twice the dimensions; use width and height sliders to set tile size": "画像を2倍の大きさにアップスケールします。幅と高さのスライダーでタイルの大きさを設定します。",
+ "Tile overlap": "Tile overlap",
+ "Upscaler": "アップスケーラー",
+ "Lanczos": "Lanczos",
+ "LDSR": "LDSR",
+ "ESRGAN_4x": "ESRGAN_4x",
+ "R-ESRGAN General 4xV3": "R-ESRGAN General 4xV3",
+ "R-ESRGAN General WDN 4xV3": "R-ESRGAN General WDN 4xV3",
+ "R-ESRGAN AnimeVideo": "R-ESRGAN AnimeVideo",
+ "R-ESRGAN 4x+": "R-ESRGAN 4x+",
+ "R-ESRGAN 4x+ Anime6B": "R-ESRGAN 4x+ Anime6B",
+ "R-ESRGAN 2x+": "R-ESRGAN 2x+",
+ "ScuNET GAN": "ScuNET GAN",
+ "ScuNET PSNR": "ScuNET PSNR",
+ "SwinIR 4x": "SwinIR 4x",
+ "Input file path": "Input file path",
+ "CRF (quality, less is better, x264 param)": "CRF (quality, less is better, x264 param)",
+ "FPS": "FPS",
+ "Seed step size": "Seed step size",
+ "Seed max distance": "Seed max distance",
+ "Start time": "Start time",
+ "End time": "End time",
+ "Single Image": "単一画像",
+ "Batch Process": "バッチ処理",
+ "Batch from Directory": "フォルダからバッチ処理",
+ "Source": "入力",
+ "Show result images": "出力画像を表示",
+ "Scale by": "倍率指定",
+ "Scale to": "解像度指定",
+ "Resize": "倍率",
+ "Crop to fit": "合うように切り抜き",
+ "Upscaler 2 visibility": "Upscaler 2 visibility",
+ "GFPGAN visibility": "GFPGAN visibility",
+ "CodeFormer visibility": "CodeFormer visibility",
+ "CodeFormer weight (0 = maximum effect, 1 = minimum effect)": "CodeFormerの重み (注:0で最大、1で最小)",
+ "Open output directory": "出力フォルダを開く",
+ "Send to txt2img": "txt2imgに送る",
+ "extras": "その他タブ",
+ "favorites": "お気に入り",
+ "Load": "読み込み",
+ "Images directory": "フォルダ",
+ "Prev batch": "前の batch",
+ "Next batch": "次の batch",
+ "First Page": "最初のぺージへ",
+ "Prev Page": "前ページへ",
+ "Page Index": "ページ番号",
+ "Next Page": "次ページへ",
+ "End Page": "最後のページへ",
+ "number of images to delete consecutively next": "次の削除で一度に削除する画像数",
+ "Delete": "削除",
+ "Generate Info": "生成情報",
+ "File Name": "ファイル名",
+ "Collect": "保存(お気に入り)",
+ "Refresh page": "ページを更新",
+ "Date to": "Date to",
+ "Number": "Number",
+ "set_index": "set_index",
+ "Checkbox": "Checkbox",
+ "A merger of the two checkpoints will be generated in your": "統合されたチェックポイントはあなたの",
+ "checkpoint": "checkpoint",
+ "directory.": "フォルダに保存されます.",
+ "Primary model (A)": "1つめのmodel (A)",
+ "Secondary model (B)": "2つめのmodel (B)",
+ "Tertiary model (C)": "3つめのmodel (C)",
+ "Custom Name (Optional)": "Custom Name (任意)",
+ "Multiplier (M) - set to 0 to get model A": "Multiplier (M) 0にすると完全にmodel Aとなります (ツールチップ参照)",
+ "Interpolation Method": "混合(Interpolation)方式",
+ "Weighted sum": "加重平均",
+ "Add difference": "差を加える",
+ "Save as float16": "float16で保存",
+ "See": "詳細な説明については",
+ "wiki": "wiki",
+ "for detailed explanation.": "を見てください。",
+ "Create embedding": "Embeddingを作る",
+ "Create hypernetwork": "Hypernetworkを作る",
+ "Preprocess images": "画像の前処理",
+ "Name": "名称",
+ "Initialization text": "Initialization text",
+ "Number of vectors per token": "Number of vectors per token",
+ "Overwrite Old Embedding": "古いEmbeddingを上書き",
+ "Modules": "モジュール",
+ "Enter hypernetwork layer structure": "Hypernetworkのレイヤー構造を入力",
+ "Select activation function of hypernetwork": "Hypernetworkの活性化関数",
+ "linear": "linear",
+ "relu": "relu",
+ "leakyrelu": "leakyrelu",
+ "elu": "elu",
+ "swish": "swish",
+ "Add layer normalization": "Add layer normalization",
+ "Use dropout": "Use dropout",
+ "Overwrite Old Hypernetwork": "古いHypernetworkを上書きする",
+ "Source directory": "入力フォルダ",
+ "Destination directory": "出力フォルダ",
+ "Existing Caption txt Action": "既存のキャプションの取り扱い",
+ "ignore": "無視する",
+ "copy": "コピーする",
+ "prepend": "先頭に加える",
+ "append": "末尾に加える",
+ "Create flipped copies": "反転画像を生成する",
+ "Split oversized images": "大きすぎる画像を分割する",
+ "Use BLIP for caption": "BLIPで説明をつける",
+ "Use deepbooru for caption": "deepbooruで説明をつける",
+ "Split image threshold": "分割する大きさの閾値",
+ "Split image overlap ratio": "Split image overlap ratio",
+ "Preprocess": "前処理開始",
+ "Train an embedding or Hypernetwork; you must specify a directory with a set of 1:1 ratio images": "EmbeddingまたはHypernetworkを学習します。1:1の比率の画像セットを含むフォルダを指定する必要があります。",
+ "[wiki]": "[wiki]",
+ "Embedding": "Embedding",
+ "Embedding Learning rate": "Embeddingの学習率(Learning rate)",
+ "Hypernetwork Learning rate": "Hypernetworkの学習率(Learning rate)",
+ "Dataset directory": "データセットフォルダ",
+ "Log directory": "ログフォルダ",
+ "Prompt template file": "プロンプトのテンプレートファイル",
+ "Max steps": "最大ステップ数",
+ "Save an image to log directory every N steps, 0 to disable": "指定したステップ数ごとに画像を生成し、ログに保存する。0で無効化。",
+ "Save a copy of embedding to log directory every N steps, 0 to disable": "指定したステップ数ごとにEmbeddingのコピーをログに保存する。0で無効化。",
+ "Save images with embedding in PNG chunks": "保存する画像にembeddingを埋め込む",
+ "Read parameters (prompt, etc...) from txt2img tab when making previews": "プレビューの作成にtxt2imgタブから読み込んだパラメータ(プロンプトなど)を使う",
+ "Train Hypernetwork": "Hypernetworkの学習を開始",
+ "Train Embedding": "Embeddingの学習を開始",
+ "Create an aesthetic embedding out of any number of images": "Create an aesthetic embedding out of any number of images",
+ "Create images embedding": "Create images embedding",
+ "Apply settings": "設定を適用",
+ "Saving images/grids": "画像/グリッドの保存",
+ "Always save all generated images": "生成された画像をすべて保存する",
+ "File format for images": "画像ファイルの保存形式",
+ "Images filename pattern": "ファイル名のパターン",
+ "Always save all generated image grids": "グリッド画像を常に保存する",
+ "File format for grids": "グリッド画像の保存形式",
+ "Add extended info (seed, prompt) to filename when saving grid": "保存するグリッド画像のファイル名に追加情報(シード値、プロンプト)を加える",
+ "Do not save grids consisting of one picture": "1画像からなるグリッド画像は保存しない",
+ "Prevent empty spots in grid (when set to autodetect)": "(自動設定のとき)グリッドに空隙が生じるのを防ぐ",
+ "Grid row count; use -1 for autodetect and 0 for it to be same as batch size": "グリッドの列数; -1で自動設定、0でバッチ生成回数と同じにする",
+ "Save text information about generation parameters as chunks to png files": "生成に関するパラメーターをPNG画像に含める",
+ "Create a text file next to every image with generation parameters.": "保存する画像とともに生成パラメータをテキストファイルで保存する",
+ "Save a copy of image before doing face restoration.": "顔修復を行う前にコピーを保存しておく。",
+ "Quality for saved jpeg images": "JPG保存時の画質",
+ "If PNG image is larger than 4MB or any dimension is larger than 4000, downscale and save copy as JPG": "PNG画像が4MBを超えるか、どちらか1辺の長さが4000を超えたなら、ダウンスケールしてコピーを別にJPGで保存する",
+ "Use original name for output filename during batch process in extras tab": "その他タブでバッチ処理をする際、元のファイル名を出力ファイル名に使う",
+ "When using 'Save' button, only save a single selected image": "\"保存\"ボタンを使うとき、単一の選択された画像のみを保存する",
+ "Do not add watermark to images": "電子透かしを画像に追加しない",
+ "Paths for saving": "保存する場所",
+ "Output directory for images; if empty, defaults to three directories below": "画像の保存先フォルダ(下項目のデフォルト値になります)",
+ "Output directory for txt2img images": "txt2imgで作った画像の保存先フォルダ",
+ "Output directory for img2img images": "img2imgで作った画像の保存先フォルダ",
+ "Output directory for images from extras tab": "その他タブで作った画像の保存先フォルダ",
+ "Output directory for grids; if empty, defaults to two directories below": "画像の保存先フォルダ(下項目のデフォルト値になります)",
+ "Output directory for txt2img grids": "txt2imgで作ったグリッドの保存先フォルダ",
+ "Output directory for img2img grids": "img2imgで作ったグリッドの保存先フォルダ",
+ "Directory for saving images using the Save button": "保存ボタンを押したときの画像の保存先フォルダ",
+ "Saving to a directory": "フォルダについて",
+ "Save images to a subdirectory": "画像をサブフォルダに保存する",
+ "Save grids to a subdirectory": "グリッドをサブフォルダに保存する",
+ "When using \"Save\" button, save images to a subdirectory": "保存ボタンを押した時、画像をサブフォルダに保存する",
+ "Directory name pattern": "フォルダ名のパターン",
+ "Max prompt words for [prompt_words] pattern": "Max prompt words for [prompt_words] pattern",
+ "Upscaling": "アップスケール",
+ "Tile size for ESRGAN upscalers. 0 = no tiling.": "ESRGANのタイルサイズ。0とするとタイルしない。",
+ "Tile overlap, in pixels for ESRGAN upscalers. Low values = visible seam.": "ESRGANのタイルの重複部分のピクセル数。少なくするとつなぎ目が見えやすくなる。",
+ "Tile size for all SwinIR.": "SwinIRのタイルサイズ",
+ "Tile overlap, in pixels for SwinIR. Low values = visible seam.": "SwinIRのタイルの重複部分のピクセル数。少なくするとつなぎ目が見えやすくなる。",
+ "LDSR processing steps. Lower = faster": "LDSR processing steps. Lower = faster",
+ "Upscaler for img2img": "img2imgで使うアップスケーラー",
+ "Upscale latent space image when doing hires. fix": "高解像度 fix時に潜在空間(latent space)の画像をアップスケールする",
+ "Face restoration": "顔修復",
+ "CodeFormer weight parameter; 0 = maximum effect; 1 = minimum effect": "CodeFormerの重みパラメーター;0が最大で1が最小",
+ "Move face restoration model from VRAM into RAM after processing": "処理終了後、顔修復モデルをVRAMからRAMへと移動する",
+ "System": "システム設定",
+ "VRAM usage polls per second during generation. Set to 0 to disable.": "生成中のVRAM使用率の取得間隔。0にすると取得しない。",
+ "Always print all generation info to standard output": "常にすべての生成に関する情報を標準出力(stdout)に出力する",
+ "Add a second progress bar to the console that shows progress for an entire job.": "ジョブ全体の進捗をコンソールに表示する2つ目のプログレスバーを追加する",
+ "Training": "学習",
+ "Move VAE and CLIP to RAM when training hypernetwork. Saves VRAM.": "hypernetworkの学習をするとき、VAEとCLIPをRAMへ退避する。VRAMが節約できます。",
+ "Filename word regex": "ファイル名の正規表現(学習用)",
+ "Filename join string": "ファイル名の結合子",
+ "Number of repeats for a single input image per epoch; used only for displaying epoch number": "Number of repeats for a single input image per epoch; used only for displaying epoch number",
+ "Save an csv containing the loss to log directory every N steps, 0 to disable": "Save an csv containing the loss to log directory every N steps, 0 to disable",
+ "Stable Diffusion": "Stable Diffusion",
+ "Checkpoints to cache in RAM": "RAMにキャッシュするCheckpoint数",
+ "Hypernetwork strength": "Hypernetwork strength",
+ "Apply color correction to img2img results to match original colors.": "元画像に合わせてimg2imgの結果を色補正する",
+ "Save a copy of image before applying color correction to img2img results": "色補正をする前の画像も保存する",
+ "With img2img, do exactly the amount of steps the slider specifies (normally you'd do less with less denoising).": "img2imgでスライダーで指定されたステップ数を正確に実行する(通常は、ノイズ除去を少なくするためにより少ないステップ数で実行します)。",
+ "Enable quantization in K samplers for sharper and cleaner results. This may change existing seeds. Requires restart to apply.": "より良い結果を得るために、Kサンプラーで量子化を有効にします。これにより既存のシードが変更される可能性があります。適用するには再起動が必要です。",
+ "Emphasis: use (text) to make model pay more attention to text and [text] to make it pay less attention": "強調: (text)とするとモデルはtextをより強く扱い、[text]とするとモデルはtextをより弱く扱います。",
+ "Use old emphasis implementation. Can be useful to reproduce old seeds.": "古い強調の実装を使う。古い生成物を再現するのに使えます。",
+ "Make K-diffusion samplers produce same images in a batch as when making a single image": "K-diffusionサンプラーによるバッチ生成時に、単一画像生成時と同じ画像を生成する",
+ "Increase coherency by padding from the last comma within n tokens when using more than 75 tokens": "75トークン以上を使用する場合、nトークン内の最後のカンマからパディングして一貫性を高める",
+ "Filter NSFW content": "NSFW(≒R-18)なコンテンツを検閲する",
+ "Interrogate Options": "Interrogate 設定",
+ "Interrogate: keep models in VRAM": "Interrogate: モデルをVRAMに保持する",
+ "Interrogate: use artists from artists.csv": "Interrogate: artists.csvにある芸術家などの名称を利用する",
+ "Interrogate: include ranks of model tags matches in results (Has no effect on caption-based interrogators).": "Interrogate: include ranks of model tags matches in results (Has no effect on caption-based interrogators).",
+ "Interrogate: num_beams for BLIP": "Interrogate: num_beams for BLIP",
+ "Interrogate: minimum description length (excluding artists, etc..)": "Interrogate: minimum description length (excluding artists, etc..)",
+ "Interrogate: maximum description length": "Interrogate: maximum description length",
+ "CLIP: maximum number of lines in text file (0 = No limit)": "CLIP: maximum number of lines in text file (0 = No limit)",
+ "Interrogate: deepbooru score threshold": "Interrogate: deepbooruで拾う単語のスコア閾値",
+ "Interrogate: deepbooru sort alphabetically": "Interrogate: deepbooruで単語をアルファベット順に並べる",
+ "use spaces for tags in deepbooru": "deepbooruのタグでスペースを使う",
+ "escape (\\) brackets in deepbooru (so they are used as literal brackets and not for emphasis)": "deepbooruで括弧をエスケープする(\\) (強調を示す()ではなく、文字通りの()であることをモデルに示すため)",
+ "User interface": "UI設定",
+ "Show progressbar": "プログレスバーを表示",
+ "Show image creation progress every N sampling steps. Set 0 to disable.": "指定したステップ数ごとに画像の生成過程を表示する。0で無効化。",
+ "Show previews of all images generated in a batch as a grid": "Show previews of all images generated in a batch as a grid",
+ "Show grid in results for web": "WebUI上でグリッド表示",
+ "Do not show any images in results for web": "WebUI上で一切画像を表示しない",
+ "Add model hash to generation information": "モデルのハッシュ値を生成情報に追加",
+ "Add model name to generation information": "モデルの名称を生成情報に追加",
+ "When reading generation parameters from text into UI (from PNG info or pasted text), do not change the selected model/checkpoint.": "テキストからUIに生成パラメータを読み込む場合(PNG情報または貼り付けられたテキストから)、選択されたモデル/チェックポイントは変更しない。",
+ "Font for image grids that have text": "画像グリッド内のテキストフォント",
+ "Enable full page image viewer": "フルページの画像ビューワーを有効化",
+ "Show images zoomed in by default in full page image viewer": "フルページ画像ビューアでデフォルトで画像を拡大して表示する",
+ "Show generation progress in window title.": "ウィンドウのタイトルで生成の進捗を表示",
+ "Quicksettings list": "クイック設定",
+ "Localization (requires restart)": "言語 (プログラムの再起動が必要)",
+ "ja_JP": "ja_JP",
+ "ru_RU": "ru_RU",
+ "Sampler parameters": "サンプラー parameters",
+ "Hide samplers in user interface (requires restart)": "使わないサンプリングアルゴリズムを隠す (再起動が必要)",
+ "eta (noise multiplier) for DDIM": "DDIMで用いるeta (noise multiplier)",
+ "eta (noise multiplier) for ancestral samplers": "ancestral サンプラーで用いるeta (noise multiplier)",
+ "img2img DDIM discretize": "img2img DDIM discretize",
+ "uniform": "uniform",
+ "quad": "quad",
+ "sigma churn": "sigma churn",
+ "sigma tmin": "sigma tmin",
+ "sigma noise": "sigma noise",
+ "Eta noise seed delta": "Eta noise seed delta",
+ "Images Browser": "画像閲覧",
+ "Preload images at startup": "起動時に画像を読み込んでおく",
+ "Number of pictures displayed on each page": "各ページに表示される画像の枚数",
+ "Minimum number of pages per load": "Minimum number of pages per load",
+ "Number of grids in each row": "Number of grids in each row",
+ "Request browser notifications": "ブラウザ通知の許可を要求する",
+ "Download localization template": "ローカライゼーション用のテンプレートをダウンロードする",
+ "Reload custom script bodies (No ui updates, No restart)": "カスタムスクリプトを再読み込み (UIは変更されず、再起動もしません。)",
+ "Restart Gradio and Refresh components (Custom Scripts, ui.py, js and css only)": "Gradioを再起動してコンポーネントをリフレッシュする (Custom Scripts, ui.py, js, cssのみ影響を受ける)",
+ "Audio": "音声",
+ "Prompt (press Ctrl+Enter or Alt+Enter to generate)": "プロンプト (Ctrl+Enter か Alt+Enter を押して生成)",
+ "Negative prompt (press Ctrl+Enter or Alt+Enter to generate)": "ネガティブ プロンプト (Ctrl+Enter か Alt+Enter を押して生成)",
+ "Add a random artist to the prompt.": "芸術家などの名称をプロンプトに追加",
+ "Read generation parameters from prompt or last generation if prompt is empty into user interface.": "プロンプトから生成パラメータを読み込むか、プロンプトが空の場合は最後の生成パラメータをユーザーインターフェースに読み込む。",
+ "Save style": "スタイルを保存する",
+ "Apply selected styles to current prompt": "現在のプロンプトに選択したスタイルを適用する",
+ "Stop processing current image and continue processing.": "現在の処理を中断し、その後の処理は続ける",
+ "Stop processing images and return any results accumulated so far.": "処理を中断し、それまでに出来た結果を表示する",
+ "Style to apply; styles have components for both positive and negative prompts and apply to both": "適用するスタイル。スタイルは、ポジティブプロンプトとネガティブプロンプトの両方のコンポーネントを持ち、両方に適用される。",
+ "Do not do anything special": "特別なことをなにもしない",
+ "Which algorithm to use to produce the image": "どのアルゴリズムを使って生成するか",
+ "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": "Euler Ancestral - 非常に独創的で、ステップ数によって全く異なる画像が得られる、ステップ数を30~40より高く設定しても効果がない。",
+ "Denoising Diffusion Implicit Models - best at inpainting": "Denoising Diffusion Implicit Models - 描き直しには最適",
+ "Produce an image that can be tiled.": "タイルとして扱える画像を生成する",
+ "Use a two step process to partially create an image at smaller resolution, upscale, and then improve details in it without changing composition": "2ステップで、まず部分的に小さい解像度で画像を作成し、その後アップスケールすることで、構図を変えずにディテールが改善されます。",
+ "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.": "アルゴリズムが画像の内容をどの程度参考にするかを決定します。0 にすると何も変わりませんし、 1 にすると全く無関係な画像になります。1.0未満の値ではスライダーで指定したサンプリングステップ数よりも少ないステップ数で処理が行われます。",
+ "How many batches of images to create": "バッチ処理を何回行うか",
+ "How many image to create in a single batch": "1回のバッチ処理で何枚の画像を生成するか",
+ "Classifier Free Guidance Scale - how strongly the image should conform to prompt - lower values produce more creative results": "Classifier Free Guidance Scale - 生成する画像がどの程度プロンプトに沿ったものになるか。 - 低い値の方がよりクリエイティブな結果を生み出します。",
+ "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": "乱数発生器の出力を決定する値。同じパラメータとシードで画像を作成すれば、同じ結果が得られます。",
+ "Set seed to -1, which will cause a new random number to be used every time": "シード値を-1に設定。つまり、毎回ランダムに生成します。",
+ "Reuse seed from last generation, mostly useful if it was randomed": "前回生成時のシード値を読み出す。(ランダム生成時に便利)",
+ "Seed of a different picture to be mixed into the generation.": "生成時に混合されることになる画像のシード値",
+ "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).": "Variationの強度。0の場合、何の効果もありません。1では、バリエーションシードで完全な画像を得ることができます(Ancestalなアルゴリズム以外では、何か(?)を得るだけです)。",
+ "Make an attempt to produce a picture similar to what would have been produced with same seed at specified resolution": "同じシードで指定された解像度の似た画像を生成することを試みる。",
+ "This text is used to rotate the feature space of the imgs embs": "This text is used to rotate the feature space of the imgs embs",
+ "Separate values for X axis using commas.": "X軸に用いる値をカンマ(,)で区切って入力してください。",
+ "Separate values for Y axis using commas.": "Y軸に用いる値をカンマ(,)で区切って入力してください。",
+ "Write image to a directory (default - log/images) and generation parameters into csv file.": "画像はフォルダ(デフォルト:log/images)に、生成パラメータはcsvファイルに書き出します。",
+ "Open images output directory": "画像の出力フォルダを開く",
+ "How much to blur the mask before processing, in pixels.": "処理前にどれだけマスクをぼかすか。px単位。",
+ "What to put inside the masked area before processing it with Stable Diffusion.": "Stable Diffusionにわたす前にマスクされたエリアに何を書き込むか",
+ "fill it with colors of the image": "元画像の色で埋める",
+ "keep whatever was there originally": "もともとあったものをそのままにする",
+ "fill it with latent space noise": "潜在空間(latent space)におけるノイズで埋める",
+ "fill it with latent space zeroes": "潜在空間(latent space)における0で埋める",
+ "Upscale masked region to target resolution, do inpainting, downscale back and paste into original image": "マスクされた領域をターゲット解像度にアップスケールし、インペイントを行い、元の解像度にダウンスケールして元の画像に貼り付けます。",
+ "Resize image to target resolution. Unless height and width match, you will get incorrect aspect ratio.": "画像をターゲット解像度にリサイズします。高さと幅が一致しない場合、アスペクト比が正しくなくなります。",
+ "Resize the image so that entirety of target resolution is filled with the image. Crop parts that stick out.": "対象の解像度に画像をフィットさせます。はみ出た部分は切り取られます。",
+ "Resize the image so that entirety of image is inside target resolution. Fill empty space with image's colors.": "画像をリサイズして、ターゲット解像度の中に収まるようにします。空白部分は画像の色で埋めます。",
+ "How many times to repeat processing an image and using it as input for the next iteration": "何回画像処理を繰り返し、次の反復処理の入力として使用するか",
+ "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.": "ループバックモードにおいて、各ループでのノイズ除去の強度はこの値によって乗算されます。1より小さければ変化が小さくなっていって、生成される画像は1つの画像に収束します。1より大きいとどんどん変化が大きくなるので、生成される画像はよりカオスになります。",
+ "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.": "SDアップスケールで、どれだけタイル間の重なりを確保するか(px単位)。タイルの一部を重複させることで、1枚の画像にした時明らかな継ぎ目がなくなります。",
+ "A directory on the same machine where the server is running.": "サーバーが稼働しているのと同じマシンのあるフォルダ",
+ "Leave blank to save images to the default path.": "空欄でデフォルトの場所へ画像を保存",
+ "Input images directory": "Input images directory",
+ "Result = A * (1 - M) + B * M": "出力されるモデル = A * (1 - M) + B * M",
+ "Result = A + (B - C) * M": "出力されるモデル = A + (B - C) * M",
+ "1st and last digit must be 1. ex:'1, 2, 1'": "最初と最後の数字は1でなければなりません。 例:'1, 2, 1'",
+ "Path to directory with input images": "入力ファイルのあるフォルダの場所",
+ "Path to directory where to write outputs": "出力を書き込むフォルダの場所",
+ "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], [prompt_words], [date], [datetime], [job_timestamp]; leave empty for default.": "以下のタグを用いてファイル名パターンを決められます: [steps], [cfg], [prompt], [prompt_no_styles], [prompt_spaces], [width], [height], [styles], [sampler], [seed], [model_hash], [prompt_words], [date], [datetime], [job_timestamp]; 空白でデフォルト設定。",
+ "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.": "このオプションを有効にすると、作成された画像にウォーターマークが追加されなくなります。警告:ウォーターマークを追加しない場合、非倫理的な行動とみなされる場合があります。",
+ "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], [prompt_words], [date], [datetime], [job_timestamp]; leave empty for default.": "以下のタグを用いてサブフォルダのフォルダ名パターンを決められます: [steps], [cfg], [prompt], [prompt_no_styles], [prompt_spaces], [width], [height], [styles], [sampler], [seed], [model_hash], [prompt_words], [date], [datetime], [job_timestamp]; 空白でデフォルト設定",
+ "Restore low quality faces using GFPGAN neural network": "GFPGANを用いて低クオリティーな顔画像を修復",
+ "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.": "この正規表現を使ってファイル名から単語を抽出し、以下のオプションで結合して学習用のラベルテキストにします。ファイル名のテキストをそのまま使用する場合は、空白にしてください。",
+ "This string will be used to join split words into a single line if the option above is enabled.": "この文字列は、上記のオプションが有効な場合に、分割された単語を1行に結合するために使用されます。",
+ "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.": "上部のクイックアクセスバーに置く設定の設定名をカンマで区切って入力。設定名については modules/shared.py を参照してください。適用するには再起動が必要です。",
+ "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.": "この値が0以外の場合、シードに追加され、Etaでサンプラーを使用する際のノイズ用の乱数生成器を初期化するのに使用されます。これを利用して、さらにバリエーション豊かな画像を作成したり、他のソフトの画像に合わせたりすることができます。",
+ "NAIConvert": "NAIから変換",
+ "History": "履歴",
+ "Enable Autocomplete": "自動補完を有効化"
+} \ No newline at end of file
diff --git a/localizations/ko_KR.json b/localizations/ko_KR.json
new file mode 100644
index 00000000..ab12c37e
--- /dev/null
+++ b/localizations/ko_KR.json
@@ -0,0 +1,497 @@
+{
+ "×": "×",
+ "•": "•",
+ "⊞": "⊞",
+ "❮": "❮",
+ "❯": "❯",
+ "⤡": "⤡",
+ " images during ": "개의 이미지를 불러왔고, 생성 기간은 ",
+ " images in this directory. Loaded ": "개의 이미지가 이 경로에 존재합니다. ",
+ " pages": "페이지로 나뉘어 표시합니다.",
+ ", divided into ": "입니다. ",
+ "1st and last digit must be 1. ex:'1, 2, 1'": "1st and last digit must be 1. ex:'1, 2, 1'",
+ "[wiki]": " [위키] 참조",
+ "A directory on the same machine where the server is running.": "WebUI 서버가 돌아가고 있는 디바이스에 존재하는 디렉토리를 선택해 주세요.",
+ "A merger of the two checkpoints will be generated in your": "체크포인트들이 병합된 결과물이 당신의",
+ "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": "난수 생성기의 결과물을 지정하는 값 - 동일한 설정값과 동일한 시드를 적용 시, 완전히 똑같은 결과물을 얻게 됩니다.",
+ "Add a random artist to the prompt.": "프롬프트에 랜덤한 작가 추가",
+ "Add a second progress bar to the console that shows progress for an entire job.": "콘솔에 전체 작업의 진행도를 보여주는 2번째 프로그레스 바 추가하기",
+ "Add difference": "차이점 추가",
+ "Add extended info (seed, prompt) to filename when saving grid": "그리드 저장 시 파일명에 추가 정보(시드, 프롬프트) 기입",
+ "Add layer normalization": "레이어 정규화(normalization) 추가",
+ "Add model hash to generation information": "생성 정보에 모델 해시 추가",
+ "Add model name to generation information": "생성 정보에 모델 이름 추가",
+ "Aesthetic imgs embedding": "스타일 이미지 임베딩",
+ "Aesthetic learning rate": "스타일 학습 수",
+ "Aesthetic steps": "스타일 스텝 수",
+ "Aesthetic text for imgs": "스타일 텍스트",
+ "Aesthetic weight": "스타일 가중치",
+ "Allowed categories for random artists selection when using the Roll button": "랜덤 버튼을 눌러 무작위 작가를 선택할 때 허용된 카테고리",
+ "Always print all generation info to standard output": "기본 아웃풋에 모든 생성 정보 항상 출력하기",
+ "Always save all generated image grids": "생성된 이미지 그리드 항상 저장하기",
+ "Always save all generated images": "생성된 이미지 항상 저장하기",
+ "api": "",
+ "append": "뒤에 삽입",
+ "Apply color correction to img2img results to match original colors.": "이미지→이미지 결과물이 기존 색상과 일치하도록 색상 보정 적용하기",
+ "Apply selected styles to current prompt": "현재 프롬프트에 선택된 스타일 적용",
+ "Apply settings": "설정 적용하기",
+ "Batch count": "배치 수",
+ "Batch from Directory": "저장 경로로부터 여러장 처리",
+ "Batch img2img": "이미지→이미지 배치",
+ "Batch Process": "이미지 여러장 처리",
+ "Batch size": "배치 크기",
+ "BSRGAN 4x": "BSRGAN 4x",
+ "built with gradio": "gradio로 제작되었습니다",
+ "Cancel generate forever": "반복 생성 취소",
+ "cfg count": "CFG 변화 횟수",
+ "CFG Scale": "CFG 스케일",
+ "cfg1 min/max": "CFG1 최소/최대",
+ "cfg2 min/max": "CFG2 최소/최대",
+ "Check progress": "진행도 체크",
+ "Check progress (first)": "진행도 체크 (처음)",
+ "checkpoint": " 체크포인트 ",
+ "Checkpoint Merger": "체크포인트 병합",
+ "Checkpoint name": "체크포인트 이름",
+ "Checkpoints to cache in RAM": "RAM에 캐싱할 체크포인트 수",
+ "Classifier Free Guidance Scale - how strongly the image should conform to prompt - lower values produce more creative results": "Classifier Free Guidance Scale - 이미지가 주어진 프롬프트를 얼마나 따를지를 정해주는 수치 - 낮은 값일수록 더 창의적인 결과물이 나옴",
+ "Click to Upload": "클릭해서 업로드하기",
+ "Clip skip": "클립 건너뛰기",
+ "CLIP: maximum number of lines in text file (0 = No limit)": "CLIP : 텍스트 파일 최대 라인 수 (0 = 제한 없음)",
+ "CodeFormer visibility": "CodeFormer 가시성",
+ "CodeFormer weight (0 = maximum effect, 1 = minimum effect)": "CodeFormer 가중치 (0 = 최대 효과, 1 = 최소 효과)",
+ "CodeFormer weight parameter; 0 = maximum effect; 1 = minimum effect": "CodeFormer 가중치 설정값 (0 = 최대 효과, 1 = 최소 효과)",
+ "Collect": "즐겨찾기",
+ "Color variation": "색깔 다양성",
+ "copy": "복사",
+ "Create a grid where images will have different parameters. Use inputs below to specify which parameters will be shared by columns and rows": "서로 다른 설정값으로 생성된 이미지의 그리드를 만듭니다. 아래의 설정으로 가로/세로에 어떤 설정값을 적용할지 선택하세요.",
+ "Create a text file next to every image with generation parameters.": "생성된 이미지마다 생성 설정값을 담은 텍스트 파일 생성하기",
+ "Create aesthetic images embedding": "스타일 이미지 임베딩 생성하기",
+ "Create embedding": "임베딩 생성",
+ "Create flipped copies": "좌우로 뒤집은 복사본 생성",
+ "Create hypernetwork": "하이퍼네트워크 생성",
+ "Create images embedding": "이미지 임베딩 생성하기",
+ "Crop and resize": "잘라낸 후 리사이징",
+ "Crop to fit": "잘라내서 맞추기",
+ "Custom Name (Optional)": "병합 모델 이름 (선택사항)",
+ "Dataset directory": "데이터셋 경로",
+ "DDIM": "DDIM",
+ "Decode CFG scale": "디코딩 CFG 스케일",
+ "Decode steps": "디코딩 스텝 수",
+ "Delete": "삭제",
+ "Denoising": "디노이징",
+ "Denoising Diffusion Implicit Models - best at inpainting": "Denoising Diffusion Implicit Models - 인페이팅에 뛰어남",
+ "Denoising strength": "디노이즈 강도",
+ "Denoising strength change factor": "디노이즈 강도 변경 배수",
+ "Destination directory": "결과물 저장 경로",
+ "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.": "알고리즘이 얼마나 원본 이미지를 반영할지를 결정하는 수치입니다. 0일 경우 아무것도 바뀌지 않고, 1일 경우 원본 이미지와 전혀 관련없는 결과물을 얻게 됩니다. 1.0 아래의 값일 경우, 설정된 샘플링 스텝 수보다 적은 스텝 수를 거치게 됩니다.",
+ "Directory for saving images using the Save button": "저장 버튼을 이용해 저장하는 이미지들의 저장 경로",
+ "Directory name pattern": "디렉토리명 패턴",
+ "directory.": "저장 경로에 저장됩니다.",
+ "Do not add watermark to images": "이미지에 워터마크 추가하지 않기",
+ "Do not do anything special": "아무것도 하지 않기",
+ "Do not save grids consisting of one picture": "이미지가 1개뿐인 그리드는 저장하지 않기",
+ "Do not show any images in results for web": "웹에서 결과창에 아무 이미지도 보여주지 않기",
+ "down": "아래쪽",
+ "Download": "다운로드",
+ "Download localization template": "현지화 템플릿 다운로드",
+ "DPM adaptive": "DPM adaptive",
+ "DPM fast": "DPM fast",
+ "DPM2": "DPM2",
+ "DPM2 a": "DPM2 a",
+ "DPM2 a Karras": "DPM2 a Karras",
+ "DPM2 Karras": "DPM2 Karras",
+ "Draw legend": "범례 그리기",
+ "Draw mask": "마스크 직접 그리기",
+ "Drop File Here": "파일을 끌어 놓으세요",
+ "Drop Image Here": "이미지를 끌어 놓으세요",
+ "Embedding": "임베딩",
+ "Embedding Learning rate": "임베딩 학습률",
+ "Emphasis: use (text) to make model pay more attention to text and [text] to make it pay less attention": "강조 : (텍스트)를 이용해 모델의 텍스트에 대한 가중치를 더 강하게 주고 [텍스트]를 이용해 더 약하게 줍니다.",
+ "Enable full page image viewer": "전체 페이지 이미지 뷰어 활성화",
+ "Enable quantization in K samplers for sharper and cleaner results. This may change existing seeds. Requires restart to apply.": "더 예리하고 깔끔한 결과물을 위해 K 샘플러들에 양자화를 적용합니다. 존재하는 시드가 변경될 수 있습니다. 재시작이 필요합니다.",
+ "End Page": "마지막 페이지",
+ "Enter hypernetwork layer structure": "하이퍼네트워크 레이어 구조 입력",
+ "Error": "오류",
+ "escape (\\) brackets in deepbooru (so they are used as literal brackets and not for emphasis)": "deepbooru에서 괄호를 역슬래시(\\)로 이스케이프 처리하기(가중치 강조가 아니라 실제 괄호로 사용되게 하기 위해)",
+ "ESRGAN_4x": "ESRGAN_4x",
+ "Eta": "Eta",
+ "eta (noise multiplier) for ancestral samplers": "ancestral 샘플러를 위한 eta(노이즈 배수)값",
+ "eta (noise multiplier) for DDIM": "DDIM을 위한 eta(노이즈 배수)값",
+ "Eta noise seed delta": "Eta 노이즈 시드 변화",
+ "Euler": "Euler",
+ "Euler a": "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": "Euler Ancestral - 매우 창의적, 스텝 수에 따라 완전히 다른 결과물이 나올 수 있음. 30~40보다 높은 스텝 수는 효과가 미미함",
+ "Existing Caption txt Action": "이미 존재하는 캡션 텍스트 처리",
+ "Extra": "고급",
+ "Extras": "부가기능",
+ "extras": "부가기능",
+ "extras history": "부가기능 기록",
+ "Face restoration": "얼굴 보정",
+ "Face restoration model": "얼굴 보정 모델",
+ "Fall-off exponent (lower=higher detail)": "감쇠 지수 (낮을수록 디테일이 올라감)",
+ "favorites": "즐겨찾기",
+ "File": "파일",
+ "File format for grids": "그리드 이미지 파일 형식",
+ "File format for images": "이미지 파일 형식",
+ "File Name": "파일 이름",
+ "File with inputs": "설정값 파일",
+ "Filename join string": "파일명 병합 문자열",
+ "Filename word regex": "파일명 정규표현식",
+ "fill": "채우기",
+ "fill it with colors of the image": "이미지의 색상으로 채우기",
+ "fill it with latent space noise": "잠재 공간 노이즈로 채우기",
+ "fill it with latent space zeroes": "잠재 공간의 0값으로 채우기",
+ "Filter NSFW content": "성인 컨텐츠 필터링하기",
+ "First Page": "처음 페이지",
+ "Firstpass height": "초기 세로길이",
+ "Firstpass width": "초기 가로길이",
+ "Font for image grids that have text": "텍스트가 존재하는 그리드 이미지의 폰트",
+ "for detailed explanation.": "를 참조하십시오.",
+ "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.": "SD 업스케일링에서 타일 간 몇 픽셀을 겹치게 할지 결정하는 설정값입니다. 타일들이 다시 한 이미지로 합쳐질 때, 눈에 띄는 이음매가 없도록 서로 겹치게 됩니다.",
+ "Generate": "생성",
+ "Generate forever": "반복 생성",
+ "Generate Info": "생성 정보",
+ "GFPGAN visibility": "GFPGAN 가시성",
+ "Grid row count; use -1 for autodetect and 0 for it to be same as batch size": "그리드 세로줄 수 : -1로 설정 시 자동 감지/0으로 설정 시 배치 크기와 동일",
+ "Height": "세로",
+ "Heun": "Heun",
+ "hide": "api 숨기기",
+ "Hide samplers in user interface (requires restart)": "사용자 인터페이스에서 숨길 샘플러 선택(재시작 필요)",
+ "Highres. fix": "고해상도 보정",
+ "History": "기록",
+ "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.": "훈련이 얼마나 빨리 이루어질지 정하는 값입니다. 값이 낮을수록 훈련 시간이 길어지고, 높은 값일수록 정확한 결과를 내는 데 실패하고 임베딩을 망가뜨릴 수 있습니다(임베딩이 망가진 경우에는 훈련 정보 텍스트박스에 손실(Loss) : nan 이라고 출력되게 됩니다. 이 경우에는 망가지지 않은 이전 백업본을 불러와야 합니다).\n\n학습률은 하나의 값으로 설정할 수도 있고, 다음 문법을 사용해 여러 값을 사용할 수도 있습니다 :\n\n학습률_1:최대 스텝수_1, 학습률_2:최대 스텝수_2, ...\n\n예 : 0.005:100, 1e-3:1000, 1e-5\n\n예의 설정값은 첫 100스텝동안 0.005의 학습률로, 그 이후 1000스텝까지는 1e-3으로, 남은 스텝은 1e-5로 훈련하게 됩니다.",
+ "How many batches of images to create": "생성할 이미지 배치 수",
+ "How many image to create in a single batch": "한 배치당 이미지 수",
+ "How many times to improve the generated image iteratively; higher values take longer; very low values can produce bad results": "생성된 이미지를 향상할 횟수; 매우 낮은 값은 만족스럽지 못한 결과물을 출력할 수 있음",
+ "How many times to repeat processing an image and using it as input for the next iteration": "이미지를 생성 후 원본으로 몇 번 반복해서 사용할지 결정하는 값",
+ "How much to blur the mask before processing, in pixels.": "이미지 생성 전 마스크를 얼마나 블러처리할지 결정하는 값. 픽셀 단위",
+ "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).": "바리에이션을 얼마나 줄지 정하는 수치 - 0일 경우 아무것도 바뀌지 않고, 1일 경우 바리에이션 시드로부터 생성된 이미지를 얻게 됩니다. (Ancestral 샘플러 제외 - 이 경우에는 좀 다른 무언가를 얻게 됩니다)",
+ "Hypernet str.": "하이퍼네트워크 강도",
+ "Hypernetwork": "하이퍼네트워크",
+ "Hypernetwork Learning rate": "하이퍼네트워크 학습률",
+ "Hypernetwork strength": "하이퍼네트워크 강도",
+ "If PNG image is larger than 4MB or any dimension is larger than 4000, downscale and save copy as JPG": "PNG 이미지가 4MB보다 크거나 가로 또는 세로길이가 4000보다 클 경우, 다운스케일 후 JPG로 복사본 저장하기",
+ "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.": "이 옵션이 활성화되면 생성된 이미지에 워터마크가 추가되지 않습니다. 경고 : 워터마크를 추가하지 않는다면, 비윤리적인 행동을 하는 중일지도 모릅니다.",
+ "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.": "이 값이 0이 아니라면, 시드에 해당 값이 더해지고, Eta가 있는 샘플러를 사용할 때 노이즈의 RNG 조정을 위해 해당 값이 사용됩니다. 이 설정으로 더 다양한 이미지를 생성하거나, 잘 알고 계시다면 특정 소프트웨어의 결과값을 재현할 수도 있습니다.",
+ "ignore": "무시",
+ "Image": "이미지",
+ "Image Browser": "이미지 브라우저",
+ "Image for img2img": "Image for img2img",
+ "Image for inpainting with mask": "마스크로 인페인팅할 이미지",
+ "Images Browser": "이미지 브라우저",
+ "Images directory": "이미지 경로",
+ "Images filename pattern": "이미지 파일명 패턴",
+ "img2img": "이미지→이미지",
+ "img2img alternative test": "이미지→이미지 대체버전 테스트",
+ "img2img DDIM discretize": "이미지→이미지 DDIM 이산화",
+ "img2img history": "이미지→이미지 기록",
+ "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.": "루프백 모드에서는 매 루프마다 디노이즈 강도에 이 값이 곱해집니다. 1보다 작을 경우 다양성이 낮아져 결과 이미지들이 고정된 형태로 모일 겁니다. 1보다 클 경우 다양성이 높아져 결과 이미지들이 갈수록 혼란스러워지겠죠.",
+ "Include Separate Images": "분리된 이미지 포함하기",
+ "Increase coherency by padding from the last comma within n tokens when using more than 75 tokens": "75개보다 많은 토큰을 사용시 마지막 쉼표로부터 N개의 토큰 이내에 패딩을 추가해 통일성 증가시키기",
+ "Initialization text": "초기화 텍스트",
+ "Inpaint": "인페인트",
+ "Inpaint at full resolution": "전체 해상도로 인페인트하기",
+ "Inpaint at full resolution padding, pixels": "전체 해상도로 인페인트시 패딩값(픽셀 단위)",
+ "Inpaint masked": "마스크만 처리",
+ "Inpaint not masked": "마스크 이외만 처리",
+ "Input directory": "인풋 이미지 경로",
+ "Interpolation Method": "보간 방법",
+ "Interrogate\nCLIP": "CLIP\n분석",
+ "Interrogate\nDeepBooru": "DeepBooru\n분석",
+ "Interrogate Options": "분석 설정",
+ "Interrogate: deepbooru score threshold": "분석 : deepbooru 점수 임계값",
+ "Interrogate: deepbooru sort alphabetically": "분석 : deepbooru 알파벳 순서로 정렬하기",
+ "Interrogate: include ranks of model tags matches in results (Has no effect on caption-based interrogators).": "분석 : 결과물에 모델 태그의 랭크 포함하기 (캡션 바탕의 분석기에는 효과 없음)",
+ "Interrogate: keep models in VRAM": "분석 : VRAM에 모델 유지하기",
+ "Interrogate: maximum description length": "분석 : 설명 최대 길이",
+ "Interrogate: minimum description length (excluding artists, etc..)": "분석 : 설명 최소 길이(작가 등등..제외)",
+ "Interrogate: num_beams for BLIP": "분석 : BLIP의 num_beams값",
+ "Interrogate: use artists from artists.csv": "분석 : artists.csv의 작가들 사용하기",
+ "Interrupt": "중단",
+ "Is negative text": "네거티브 텍스트일시 체크",
+ "Just resize": "리사이징",
+ "Keep -1 for seeds": "시드값 -1로 유지",
+ "keep whatever was there originally": "이미지 원본 유지",
+ "Label": "라벨",
+ "Lanczos": "Lanczos",
+ "Last prompt:": "마지막 프롬프트 : ",
+ "Last saved hypernetwork:": "마지막으로 저장된 하이퍼네트워크 : ",
+ "Last saved image:": "마지막으로 저장된 이미지 : ",
+ "latent noise": "잠재 노이즈",
+ "latent nothing": "잠재 공백",
+ "LDSR": "LDSR",
+ "LDSR processing steps. Lower = faster": "LDSR 스텝 수. 낮은 값 = 빠른 속도",
+ "leakyrelu": "leakyrelu",
+ "Leave blank to save images to the default path.": "기존 저장 경로에 이미지들을 저장하려면 비워두세요.",
+ "left": "왼쪽",
+ "linear": "linear",
+ "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.": "설정 탭이 아니라 상단의 빠른 설정 바에 위치시킬 설정 이름을 쉼표로 분리해서 입력하십시오. 설정 이름은 modules/shared.py에서 찾을 수 있습니다. 재시작이 필요합니다.",
+ "LMS": "LMS",
+ "LMS Karras": "LMS Karras",
+ "Load": "불러오기",
+ "Loading...": "로딩 중...",
+ "Localization (requires restart)": "현지화 (재시작 필요)",
+ "Log directory": "로그 경로",
+ "Loopback": "루프백",
+ "Loops": "루프 수",
+ "Loss:": "손실(Loss) : ",
+ "Make an attempt to produce a picture similar to what would have been produced with same seed at specified resolution": "동일한 시드 값으로 생성되었을 이미지를 주어진 해상도로 최대한 유사하게 재현합니다.",
+ "Make K-diffusion samplers produce same images in a batch as when making a single image": "K-diffusion 샘플러들이 단일 이미지를 생성하는 것처럼 배치에서도 동일한 이미지를 생성하게 하기",
+ "Make Zip when Save?": "저장 시 Zip 생성하기",
+ "Mask": "마스크",
+ "Mask blur": "마스크 블러",
+ "Mask mode": "마스크 모드",
+ "Masked content": "마스크된 부분",
+ "Masking mode": "마스킹 모드",
+ "Max prompt words for [prompt_words] pattern": "[prompt_words] 패턴의 최대 프롬프트 단어 수",
+ "Max steps": "최대 스텝 수",
+ "Minimum number of pages per load": "한번 불러올 때마다 불러올 최소 페이지 수",
+ "Modules": "모듈",
+ "Move face restoration model from VRAM into RAM after processing": "처리가 완료되면 얼굴 보정 모델을 VRAM에서 RAM으로 옮기기",
+ "Move VAE and CLIP to RAM when training hypernetwork. Saves VRAM.": "하이퍼네트워크 훈련 진행 시 VAE와 CLIP을 RAM으로 옮기기. VRAM이 절약됩니다.",
+ "Multiplier (M) - set to 0 to get model A": "배율 (M) - 0으로 적용하면 모델 A를 얻게 됩니다",
+ "Name": "이름",
+ "Negative prompt": "네거티브 프롬프트",
+ "Negative prompt (press Ctrl+Enter or Alt+Enter to generate)": "네거티브 프롬프트 입력(Ctrl+Enter나 Alt+Enter로 생성 시작)",
+ "Next batch": "다음 묶음",
+ "Next Page": "다음 페이지",
+ "None": "없음",
+ "Nothing": "없음",
+ "Nothing found in the image.": "Nothing found in the image.",
+ "Number of grids in each row": "각 세로줄마다 표시될 그리드 수",
+ "number of images to delete consecutively next": "연속적으로 삭제할 이미지 수",
+ "Number of pictures displayed on each page": "각 페이지에 표시될 이미지 수",
+ "Number of repeats for a single input image per epoch; used only for displaying epoch number": "세대(Epoch)당 단일 인풋 이미지의 반복 횟수 - 세대(Epoch) 숫자를 표시하는 데에만 사용됩니다. ",
+ "Number of vectors per token": "토큰별 벡터 수",
+ "Open for Clip Aesthetic!": "클립 스타일 기능을 활성화하려면 클릭!",
+ "Open images output directory": "이미지 저장 경로 열기",
+ "Open output directory": "저장 경로 열기",
+ "or": "또는",
+ "original": "원본 유지",
+ "Original negative prompt": "기존 네거티브 프롬프트",
+ "Original prompt": "기존 프롬프트",
+ "Outpainting direction": "아웃페인팅 방향",
+ "Outpainting mk2": "아웃페인팅 마크 2",
+ "Output directory": "이미지 저장 경로",
+ "Output directory for grids; if empty, defaults to two directories below": "그리드 이미지 저장 경로 - 비워둘 시 하단의 2가지 기본 경로로 설정됨",
+ "Output directory for images from extras tab": "부가기능 탭 저장 경로",
+ "Output directory for images; if empty, defaults to three directories below": "이미지 저장 경로 - 비워둘 시 하단의 3가지 기본 경로로 설정됨",
+ "Output directory for img2img grids": "이미지→이미지 그리드 저장 경로",
+ "Output directory for img2img images": "이미지→이미지 저장 경로",
+ "Output directory for txt2img grids": "텍스트→이미지 그리드 저장 경로",
+ "Output directory for txt2img images": "텍스트→이미지 저장 경로",
+ "Override `Denoising strength` to 1?": "디노이즈 강도를 1로 적용할까요?",
+ "Override `prompt` to the same value as `original prompt`?(and `negative prompt`)": "프롬프트 값을 기존 프롬프트와 동일하게 적용할까요?(네거티브 프롬프트 포함)",
+ "Override `Sampling method` to Euler?(this method is built for it)": "샘플링 방법을 Euler로 적용할까요?(이 기능은 해당 샘플러를 위해 만들어져 있습니다)",
+ "Override `Sampling Steps` to the same value as `Decode steps`?": "샘플링 스텝 수를 디코딩 스텝 수와 동일하게 적용할까요?",
+ "Overwrite Old Embedding": "기존 임베딩 덮어쓰기",
+ "Overwrite Old Hypernetwork": "기존 하이퍼네트워크 덮어쓰기",
+ "Page Index": "페이지 인덱스",
+ "parameters": "설정값",
+ "Path to directory where to write outputs": "결과물을 출력할 경로",
+ "Path to directory with input images": "인풋 이미지가 있는 경로",
+ "Paths for saving": "저장 경로",
+ "Pixels to expand": "확장할 픽셀 수",
+ "PLMS": "PLMS",
+ "PNG Info": "PNG 정보",
+ "Poor man's outpainting": "가난뱅이의 아웃페인팅",
+ "Preload images at startup": "WebUI 가동 시 이미지 프리로드하기",
+ "Preparing dataset from": "준비된 데이터셋 경로 : ",
+ "prepend": "앞에 삽입",
+ "Preprocess": "전처리",
+ "Preprocess images": "이미지 전처리",
+ "Prev batch": "이전 묶음",
+ "Prev Page": "이전 페이지",
+ "Prevent empty spots in grid (when set to autodetect)": "(자동 감지 사용시)그리드에 빈칸이 생기는 것 방지하기",
+ "Primary model (A)": "주 모델 (A)",
+ "Process an image, use it as an input, repeat.": "이미지를 생성하고, 생성한 이미지를 다시 원본으로 사용하는 과정을 반복합니다.",
+ "Process images in a directory on the same machine where the server is running.": "WebUI 서버가 돌아가고 있는 디바이스에 존재하는 디렉토리의 이미지들을 처리합니다.",
+ "Produce an image that can be tiled.": "타일링 가능한 이미지를 생성합니다.",
+ "Prompt": "프롬프트",
+ "Prompt (press Ctrl+Enter or Alt+Enter to generate)": "프롬프트 입력(Ctrl+Enter나 Alt+Enter로 생성 시작)",
+ "Prompt matrix": "프롬프트 매트릭스",
+ "Prompt order": "프롬프트 순서",
+ "Prompt S/R": "프롬프트 스타일 변경",
+ "Prompt template file": "프롬프트 템플릿 파일 경로",
+ "Prompts": "프롬프트",
+ "Prompts from file or textbox": "파일이나 텍스트박스로부터 프롬프트 불러오기",
+ "Put variable parts at start of prompt": "변경되는 프롬프트를 앞에 위치시키기",
+ "quad": "quad",
+ "Quality for saved jpeg images": "저장된 jpeg 이미지들의 품질",
+ "Quicksettings list": "빠른 설정 리스트",
+ "R-ESRGAN 4x+ Anime6B": "R-ESRGAN 4x+ Anime6B",
+ "Random": "랜덤",
+ "Random grid": "랜덤 그리드",
+ "Randomness": "랜덤성",
+ "Read generation parameters from prompt or last generation if prompt is empty into user interface.": "클립보드에 복사된 정보로부터 설정값 읽어오기/프롬프트창이 비어있을경우 제일 최근 설정값 불러오기",
+ "Read parameters (prompt, etc...) from txt2img tab when making previews": "프리뷰 이미지 생성 시 텍스트→이미지 탭에서 설정값(프롬프트 등) 읽어오기",
+ "Recommended settings: Sampling Steps: 80-100, Sampler: Euler a, Denoising strength: 0.8": "추천 설정값 - 샘플링 스텝 수 : 80-100 , 샘플러 : Euler a, 디노이즈 강도 : 0.8",
+ "Reload custom script bodies (No ui updates, No restart)": "커스텀 스크립트 리로드하기(UI 업데이트 없음, 재시작 없음)",
+ "relu": "relu",
+ "Renew Page": "Renew Page",
+ "Request browser notifications": "브라우저 알림 권한 요청",
+ "Resize": "리사이징 배수",
+ "Resize and fill": "리사이징 후 채우기",
+ "Resize image to target resolution. Unless height and width match, you will get incorrect aspect ratio.": "설정된 해상도로 이미지 리사이징을 진행합니다. 원본과 가로/세로 길이가 일치하지 않을 경우, 부정확한 화면비의 이미지를 얻게 됩니다.",
+ "Resize mode": "리사이징 모드",
+ "Resize seed from height": "시드 리사이징 가로길이",
+ "Resize seed from width": "시드 리사이징 세로길이",
+ "Resize the image so that entirety of image is inside target resolution. Fill empty space with image's colors.": "이미지 전체가 설정된 해상도 내부에 들어가게 리사이징을 진행합니다. 빈 공간은 이미지의 색상으로 채웁니다.",
+ "Resize the image so that entirety of target resolution is filled with the image. Crop parts that stick out.": "설정된 해상도 전체가 이미지로 가득차게 리사이징을 진행합니다. 튀어나오는 부분은 잘라냅니다.",
+ "Restart Gradio and Refresh components (Custom Scripts, ui.py, js and css only)": "Gradio를 재시작하고 컴포넌트 새로고침하기 (커스텀 스크립트, ui.py, js, css만 해당됨)",
+ "Restore faces": "얼굴 보정",
+ "Restore low quality faces using GFPGAN neural network": "GFPGAN 신경망을 이용해 저품질의 얼굴을 보정합니다.",
+ "Result = A * (1 - M) + B * M": "결과물 = A * (1 - M) + B * M",
+ "Result = A + (B - C) * M": "결과물 = A + (B - C) * M",
+ "Reuse seed from last generation, mostly useful if it was randomed": "이전 생성에서 사용된 시드를 불러옵니다. 랜덤하게 생성했을 시 도움됨",
+ "right": "오른쪽",
+ "Run": "가동",
+ "Sampler": "샘플러",
+ "Sampler parameters": "샘플러 설정값",
+ "Sampling method": "샘플링 방법",
+ "Sampling Steps": "샘플링 스텝 수",
+ "Save": "저장",
+ "Save a copy of embedding to log directory every N steps, 0 to disable": "N스텝마다 로그 경로에 임베딩을 저장합니다, 비활성화하려면 0으로 설정하십시오.",
+ "Save a copy of image before applying color correction to img2img results": "이미지→이미지 결과물에 색상 보정을 진행하기 전 이미지의 복사본을 저장하기",
+ "Save a copy of image before doing face restoration.": "얼굴 보정을 진행하기 전 이미지의 복사본을 저장하기",
+ "Save an csv containing the loss to log directory every N steps, 0 to disable": "N스텝마다 로그 경로에 손실(Loss)을 포함하는 csv 파일을 저장합니다, 비활성화하려면 0으로 설정하십시오.",
+ "Save an image to log directory every N steps, 0 to disable": "N스텝마다 로그 경로에 이미지를 저장합니다, 비활성화하려면 0으로 설정하십시오.",
+ "Save as float16": "float16으로 저장",
+ "Save grids to a subdirectory": "그리드 이미지를 하위 디렉토리에 저장하기",
+ "Save images to a subdirectory": "이미지를 하위 디렉토리에 저장하기",
+ "Save images with embedding in PNG chunks": "PNG 청크로 이미지에 임베딩을 포함시켜 저장",
+ "Save style": "스타일 저장",
+ "Save text information about generation parameters as chunks to png files": "이미지 생성 설정값을 PNG 청크에 텍스트로 저장",
+ "Saving images/grids": "이미지/그리드 저장",
+ "Saving to a directory": "디렉토리에 저장",
+ "Scale by": "스케일링 배수 지정",
+ "Scale to": "스케일링 사이즈 지정",
+ "Script": "스크립트",
+ "ScuNET GAN": "ScuNET GAN",
+ "ScuNET PSNR": "ScuNET PSNR",
+ "SD upscale": "SD 업스케일링",
+ "Secondary model (B)": "2차 모델 (B)",
+ "See": "자세한 설명은",
+ "Seed": "시드",
+ "Seed of a different picture to be mixed into the generation.": "결과물에 섞일 다른 그림의 시드",
+ "Select activation function of hypernetwork": "하이퍼네트워크 활성화 함수 선택",
+ "Select which Real-ESRGAN models to show in the web UI. (Requires restart)": "WebUI에 표시할 Real-ESRGAN 모델을 선택하십시오. (재시작 필요)",
+ "Send to extras": "부가기능으로 전송",
+ "Send to img2img": "이미지→이미지로 전송",
+ "Send to inpaint": "인페인트로 전송",
+ "Send to txt2img": "텍스트→이미지로 전송",
+ "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)": "(|)를 이용해 프롬프트를 분리할 시 첫 프롬프트를 제외하고 모든 프롬프트의 조합마다 이미지를 생성합니다. 첫 프롬프트는 모든 조합에 포함되게 됩니다.",
+ "Separate values for X axis using commas.": "쉼표로 X축에 적용할 값 분리",
+ "Separate values for Y axis using commas.": "쉼표로 Y축에 적용할 값 분리",
+ "Set seed to -1, which will cause a new random number to be used every time": "시드를 -1로 적용 - 매번 랜덤한 시드가 적용되게 됩니다.",
+ "set_index": "set_index",
+ "Settings": "설정",
+ "should be 2 or lower.": "이 2 이하여야 합니다.",
+ "Show generation progress in window title.": "창 타이틀에 생성 진행도 보여주기",
+ "Show grid in results for web": "웹에서 결과창에 그리드 보여주기",
+ "Show image creation progress every N sampling steps. Set 0 to disable.": "N번째 샘플링 스텝마다 이미지 생성 과정 보이기 - 비활성화하려면 0으로 설정",
+ "Show images zoomed in by default in full page image viewer": "전체 페이지 이미지 뷰어에서 기본값으로 이미지 확대해서 보여주기",
+ "Show previews of all images generated in a batch as a grid": "배치에서 생성된 모든 이미지의 미리보기를 그리드 형식으로 보여주기",
+ "Show progressbar": "프로그레스 바 보이기",
+ "Show result images": "이미지 결과 보이기",
+ "Show Textbox": "텍스트박스 보이기",
+ "Sigma adjustment for finding noise for image": "이미지 노이즈를 찾기 위해 시그마 조정",
+ "Sigma Churn": "시그마 섞기",
+ "sigma churn": "시그마 섞기",
+ "Sigma max": "시그마 최댓값",
+ "Sigma min": "시그마 최솟값",
+ "Sigma noise": "시그마 노이즈",
+ "sigma noise": "시그마 노이즈",
+ "sigma tmin": "시그마 tmin",
+ "Single Image": "단일 이미지",
+ "Skip": "건너뛰기",
+ "Slerp angle": "구면 선형 보간 각도",
+ "Slerp interpolation": "구면 선형 보간",
+ "Source": "원본",
+ "Source directory": "원본 경로",
+ "Split image overlap ratio": "이미지 분할 겹침 비율",
+ "Split image threshold": "이미지 분할 임계값",
+ "Split oversized images": "사이즈가 큰 이미지 분할하기",
+ "Stable Diffusion": "Stable Diffusion",
+ "Stable Diffusion checkpoint": "Stable Diffusion 체크포인트",
+ "step count": "스텝 변화 횟수",
+ "step1 min/max": "스텝1 최소/최대",
+ "step2 min/max": "스텝2 최소/최대",
+ "Step:": "Step:",
+ "Steps": "스텝 수",
+ "Stop At last layers of CLIP model": "CLIP 모델의 n번째 레이어에서 멈추기",
+ "Stop processing current image and continue processing.": "현재 진행중인 이미지 생성을 중단하고 작업을 계속하기",
+ "Stop processing images and return any results accumulated so far.": "이미지 생성을 중단하고 지금까지 진행된 결과물 출력",
+ "Style 1": "스타일 1",
+ "Style 2": "스타일 2",
+ "Style to apply; styles have components for both positive and negative prompts and apply to both": "적용할 스타일 - 스타일은 긍정/부정 프롬프트 모두에 대한 설정값을 가지고 있고 양쪽 모두에 적용 가능합니다.",
+ "SwinIR 4x": "SwinIR 4x",
+ "Sys VRAM:": "시스템 VRAM : ",
+ "System": "시스템",
+ "Tertiary model (C)": "3차 모델 (C)",
+ "Textbox": "텍스트박스",
+ "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.": "이 정규표현식은 파일명으로부터 단어를 추출하는 데 사용됩니다. 추출된 단어들은 하단의 설정을 이용해 라벨 텍스트로 변환되어 훈련에 사용됩니다. 파일명 텍스트를 유지하려면 비워두십시오.",
+ "This string will be used to join split words into a single line if the option above is enabled.": "이 문자열은 상단 설정이 활성화되어있을 때 분리된 단어들을 한 줄로 합치는 데 사용됩니다.",
+ "This text is used to rotate the feature space of the imgs embs": "이 텍스트는 이미지 임베딩의 특징 공간을 회전하는 데 사용됩니다.",
+ "Tile overlap": "타일 겹침",
+ "Tile overlap, in pixels for ESRGAN upscalers. Low values = visible seam.": "ESRGAN 업스케일러들의 타일 중첩 수치, 픽셀 단위. 낮은 값 = 눈에 띄는 이음매.",
+ "Tile overlap, in pixels for SwinIR. Low values = visible seam.": "SwinIR의 타일 중첩 수치, 픽셀 단위. 낮은 값 = 눈에 띄는 이음매.",
+ "Tile size for all SwinIR.": "SwinIR의 타일 사이즈.",
+ "Tile size for ESRGAN upscalers. 0 = no tiling.": "ESRGAN 업스케일러들의 타일 사이즈. 0 = 타일링 없음.",
+ "Tiling": "타일링",
+ "Time taken:": "소요 시간 : ",
+ "Torch active/reserved:": "활성화/예약된 Torch 양 : ",
+ "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%).": "활성화된 Torch : 생성 도중 캐시된 데이터를 포함해 사용된 VRAM의 최대량\n예약된 Torch : 활성화되고 캐시된 모든 데이터를 포함해 Torch에게 할당된 VRAM의 최대량\n시스템 VRAM : 모든 어플리케이션에 할당된 VRAM 최대량 / 총 GPU VRAM (최고 이용도%)",
+ "Train": "훈련",
+ "Train an embedding or Hypernetwork; you must specify a directory with a set of 1:1 ratio images": "임베딩이나 하이퍼네트워크를 훈련시킵니다. 1:1 비율의 이미지가 있는 경로를 지정해야 합니다.",
+ "Train Embedding": "임베딩 훈련",
+ "Train Hypernetwork": "하이퍼네트워크 훈련",
+ "Training": "훈련",
+ "txt2img": "텍스트→이미지",
+ "txt2img history": "텍스트→이미지 기록",
+ "uniform": "uniform",
+ "up": "위쪽",
+ "Upload mask": "마스크 업로드하기",
+ "Upscale latent space image when doing hires. fix": "고해상도 보정 사용시 잠재 공간 이미지 업스케일하기",
+ "Upscale masked region to target resolution, do inpainting, downscale back and paste into original image": "마스크된 부분을 설정된 해상도로 업스케일하고, 인페인팅을 진행한 뒤, 다시 다운스케일 후 원본 이미지에 붙여넣습니다.",
+ "Upscaler": "업스케일러",
+ "Upscaler 1": "업스케일러 1",
+ "Upscaler 2": "업스케일러 2",
+ "Upscaler 2 visibility": "업스케일러 2 가시성",
+ "Upscaler for img2img": "이미지→이미지 업스케일러",
+ "Upscaling": "업스케일링",
+ "Use a two step process to partially create an image at smaller resolution, upscale, and then improve details in it without changing composition": "저해상도 이미지를 1차적으로 생성 후 업스케일을 진행하여, 이미지의 전체적인 구성을 바꾸지 않고 세부적인 디테일을 향상시킵니다.",
+ "Use an empty output directory to save pictures normally instead of writing to the output directory.": "저장 경로를 비워두면 기본 저장 폴더에 이미지들이 저장됩니다.",
+ "Use BLIP for caption": "캡션에 BLIP 사용",
+ "Use deepbooru for caption": "캡션에 deepbooru 사용",
+ "Use dropout": "드롭아웃 사용",
+ "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], [prompt_words], [date], [datetime], [job_timestamp]; leave empty for default.": "다음 태그들을 사용해 이미지 파일명 형식을 결정하세요 : [steps], [cfg], [prompt], [prompt_no_styles], [prompt_spaces], [width], [height], [styles], [sampler], [seed], [model_hash], [prompt_words], [date], [datetime], [job_timestamp]. 비워두면 기본값으로 설정됩니다.",
+ "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], [prompt_words], [date], [datetime], [job_timestamp]; leave empty for default.": "다음 태그들을 사용해 이미지와 그리드의 하위 디렉토리명의 형식을 결정하세요 : [steps], [cfg], [prompt], [prompt_no_styles], [prompt_spaces], [width], [height], [styles], [sampler], [seed], [model_hash], [prompt_words], [date], [datetime], [job_timestamp]. 비워두면 기본값으로 설정됩니다.",
+ "Use old emphasis implementation. Can be useful to reproduce old seeds.": "옛 방식의 강조 구현을 사용합니다. 옛 시드를 재현하는 데 효과적일 수 있습니다.",
+ "Use original name for output filename during batch process in extras tab": "부가기능 탭에서 이미지를 여러장 처리 시 결과물 파일명에 기존 파일명 사용하기",
+ "use spaces for tags in deepbooru": "deepbooru에서 태그에 공백 사용",
+ "User interface": "사용자 인터페이스",
+ "Var. seed": "바리에이션 시드",
+ "Var. strength": "바리에이션 강도",
+ "Variation seed": "바리에이션 시드",
+ "Variation strength": "바리에이션 강도",
+ "view": "api 보이기",
+ "VRAM usage polls per second during generation. Set to 0 to disable.": "생성 도중 초당 VRAM 사용량 폴링 수. 비활성화하려면 0으로 설정하십시오.",
+ "Weighted sum": "가중 합",
+ "What to put inside the masked area before processing it with Stable Diffusion.": "Stable Diffusion으로 이미지를 생성하기 전 마스크된 부분에 무엇을 채울지 결정하는 설정값",
+ "When reading generation parameters from text into UI (from PNG info or pasted text), do not change the selected model/checkpoint.": "PNG 정보나 붙여넣은 텍스트로부터 생성 설정값을 읽어올 때, 선택된 모델/체크포인트는 변경하지 않기.",
+ "When using \"Save\" button, save images to a subdirectory": "저장 버튼 사용시, 이미지를 하위 디렉토리에 저장하기",
+ "When using 'Save' button, only save a single selected image": "저장 버튼 사용시, 선택된 이미지 1개만 저장하기",
+ "Which algorithm to use to produce the image": "이미지를 생성할 때 사용할 알고리즘",
+ "Width": "가로",
+ "wiki": " 위키",
+ "Will upscale the image to twice the dimensions; use width and height sliders to set tile size": "이미지를 설정된 사이즈의 2배로 업스케일합니다. 상단의 가로와 세로 슬라이더를 이용해 타일 사이즈를 지정하세요.",
+ "With img2img, do exactly the amount of steps the slider specifies (normally you'd do less with less denoising).": "이미지→이미지 진행 시, 슬라이더로 설정한 스텝 수를 정확히 실행하기 (일반적으로 디노이즈 강도가 낮을수록 실제 설정된 스텝 수보다 적게 진행됨)",
+ "Write image to a directory (default - log/images) and generation parameters into csv file.": "이미지를 경로에 저장하고, 설정값들을 csv 파일로 저장합니다. (기본 경로 - log/images)",
+ "X type": "X축",
+ "X values": "X 설정값",
+ "x/y change": "X/Y축 변경",
+ "X/Y plot": "X/Y 플롯",
+ "Y type": "Y축",
+ "Y values": "Y 설정값"
+} \ No newline at end of file
diff --git a/localizations/ru_RU.json b/localizations/ru_RU.json
new file mode 100644
index 00000000..664d36ea
--- /dev/null
+++ b/localizations/ru_RU.json
@@ -0,0 +1,475 @@
+{
+ "⤡": "⤡",
+ "⊞": "⊞",
+ "×": "×",
+ "❮": "❮",
+ "❯": "❯",
+ "Loading...": "Загрузка...",
+ "view": "просмотр",
+ "api": "api",
+ "•": "•",
+ "built with gradio": "На основе Gradio",
+ "Stable Diffusion checkpoint": "Веса Stable Diffusion",
+ "txt2img": "текст-в-рисунок",
+ "img2img": "рисунок-в-рисунок",
+ "Extras": "Дополнения",
+ "PNG Info": "Информация о PNG",
+ "Image Browser": "Просмотр изображений",
+ "History": "Журнал",
+ "Checkpoint Merger": "Слияние весов",
+ "Train": "Обучение",
+ "Create aesthetic embedding": "Создать эмбеддинг эстетики",
+ "Settings": "Настройки",
+ "Prompt": "Запрос",
+ "Negative prompt": "Исключающий запрос",
+ "Run": "Запустить",
+ "Skip": "Пропустить",
+ "Interrupt": "Прервать",
+ "Generate": "Создать",
+ "Style 1": "Стиль 1",
+ "Style 2": "Стиль 2",
+ "Label": "Метка",
+ "File": "Файл",
+ "Drop File Here": "Перетащите файл сюда",
+ "-": "-",
+ "or": "или",
+ "Click to Upload": "Нажмите, чтобы загрузить",
+ "Image": "Рисунок",
+ "Check progress": "Узнать состояние",
+ "Check progress (first)": "Узнать состояние первого",
+ "Sampling Steps": "Шагов семплера",
+ "Sampling method": "Метод семплирования",
+ "Euler a": "Euler a",
+ "Euler": "Euler",
+ "LMS": "LMS",
+ "Heun": "Heun",
+ "DPM2": "DPM2",
+ "DPM2 a": "DPM2 a",
+ "DPM fast": "DPM fast",
+ "DPM adaptive": "DPM adaptive",
+ "LMS Karras": "LMS Karras",
+ "DPM2 Karras": "DPM2 Karras",
+ "DPM2 a Karras": "DPM2 a Karras",
+ "DDIM": "DDIM",
+ "PLMS": "PLMS",
+ "Width": "Ширина",
+ "Height": "Высота",
+ "Restore faces": "Восстановить лица",
+ "Tiling": "Замощение",
+ "Highres. fix": "HD-режим",
+ "Firstpass width": "Ширина первого прохода",
+ "Firstpass height": "Высота первого прохода",
+ "Denoising strength": "Сила шумоподавления",
+ "Batch count": "Рисунков подряд",
+ "Batch size": "Рисунков параллельно",
+ "CFG Scale": "Близость к запросу",
+ "Seed": "Семя",
+ "Extra": "Дополнения",
+ "Variation seed": "Вариация семени",
+ "Variation strength": "Вариация шумоподавления",
+ "Resize seed from width": "Поправка в семя от ширины",
+ "Resize seed from height": "Поправка в семя от высоты",
+ "Open for Clip Aesthetic!": "Clip-эстетика!",
+ "▼": "▼",
+ "Aesthetic weight": "Вес эстетики",
+ "Aesthetic steps": "Шагов эстетики",
+ "Aesthetic learning rate": "Скорость обучения эстетики",
+ "Slerp interpolation": "Slerp-интерполяция",
+ "Aesthetic imgs embedding": "Рисунки - эмбеддинги эстетики",
+ "None": "Ничего",
+ "Aesthetic text for imgs": "Имя эстетики рисунков",
+ "Slerp angle": "Угол slerp",
+ "Is negative text": "Это текст для исключения",
+ "Script": "Скрипт",
+ "Prompt matrix": "Матрица запросов",
+ "Prompts from file or textbox": "Запросы из файла или текста",
+ "X/Y plot": "X/Y-график",
+ "Put variable parts at start of prompt": "Переменное начало запроса",
+ "Show Textbox": "Показать текстовый ввод",
+ "File with inputs": "Файл входа",
+ "Prompts": "Запросы",
+ "X type": "Ось X",
+ "Nothing": "Ничего",
+ "Var. seed": "Вариация семени",
+ "Var. strength": "Вариация силы",
+ "Steps": "Число шагов",
+ "Prompt S/R": "Вариация запроса",
+ "Prompt order": "Порядок запросов",
+ "Sampler": "Семплер",
+ "Checkpoint name": "Имя файла весов",
+ "Hypernetwork": "Гиперсеть",
+ "Hypernet str.": "Строка гиперсети",
+ "Sigma Churn": "Возмущение сигмы",
+ "Sigma min": "Мин. сигма",
+ "Sigma max": "Макс. сигма",
+ "Sigma noise": "Сигма-шум",
+ "Eta": "Расчётное время",
+ "Clip skip": "Пропустить Clip",
+ "Denoising": "Шумоподавление",
+ "X values": "Значения X",
+ "Y type": "Тип Y",
+ "Y values": "Значения Y",
+ "Draw legend": "Легенда графика",
+ "Include Separate Images": "Включить отдельные рисунки",
+ "Keep -1 for seeds": "-1 для семени",
+ "Drop Image Here": "Перетащите рисунок сюда",
+ "Save": "Сохранить",
+ "Send to img2img": "В рисунок-в-рисунок",
+ "Send to inpaint": "В режим врисовывания",
+ "Send to extras": "В дополнения",
+ "Make Zip when Save?": "Создать zip при сохранении?",
+ "Textbox": "Текст",
+ "Interrogate\nCLIP": "Распознавание\nCLIP",
+ "Interrogate\nDeepBooru": "Распознавание\nDeepBooru",
+ "Inpaint": "врисовать",
+ "Batch img2img": "рисунок-в-рисунок (набор)",
+ "Image for img2img": "рисунок-в-рисунок (вход)",
+ "Image for inpainting with mask": "врисовать (вход с трафаретом)",
+ "Mask": "Трафарет",
+ "Mask blur": "Размытие трафарета",
+ "Mask mode": "Режим трафарета",
+ "Draw mask": "Нарисовать трафарет",
+ "Upload mask": "Загрузить трафарет",
+ "Masking mode": "Режим трафарета",
+ "Inpaint masked": "Внутри трафарета",
+ "Inpaint not masked": "Вне трафарета",
+ "Masked content": "Под трафаретом",
+ "fill": "залить",
+ "original": "сохранить",
+ "latent noise": "латентный шум",
+ "latent nothing": "латентная пустота",
+ "Inpaint at full resolution": "Врисовать при полном разрешении",
+ "Inpaint at full resolution padding, pixels": "Врисовать с достройкой до полного разрешения, в пикселях",
+ "Process images in a directory on the same machine where the server is running.": "Обрабатывать рисунки на том же компьютере, где сервер",
+ "Use an empty output directory to save pictures normally instead of writing to the output directory.": "Использовать пустую папку вместо того, чтобы выводить в output",
+ "Disabled when launched with --hide-ui-dir-config.": "Выключено при запуске с --hide-ui-dir-config",
+ "Input directory": "Папка входа",
+ "Output directory": "Папка выхода",
+ "Resize mode": "Масштабирование",
+ "Just resize": "Только сжать",
+ "Crop and resize": "Сжать и обрезать",
+ "Resize and fill": "Сжать и залить",
+ "img2img alternative test": "рисунок-в-рисунок (альтернатива)",
+ "Loopback": "Прокручивание",
+ "Outpainting mk2": "Обрисовыватель mk2",
+ "Poor man's outpainting": "Хоть какой-то обрисовыватель",
+ "SD upscale": "SD-апскейл",
+ "should be 2 or lower.": "должно быть меньше равно 2",
+ "Override `Sampling method` to Euler?(this method is built for it)": "Сменить метод семплирования на метод Эйлера?(скрипт строился с его учётом)",
+ "Override `prompt` to the same value as `original prompt`?(and `negative prompt`)": "Сменить `запрос` на `изначальный запрос`?(и `запрос-исключение`)",
+ "Original prompt": "Изначальный запрос",
+ "Original negative prompt": "Изначальный запрос-исключение",
+ "Override `Sampling Steps` to the same value as `Decode steps`?": "Сменить число шагов на число шагов декодирования?",
+ "Decode steps": "Шагов декодирования",
+ "Override `Denoising strength` to 1?": "Сменить силу шумоподавления на 1?",
+ "Decode CFG scale": "Близость к запросу декодирования",
+ "Randomness": "Случайность",
+ "Sigma adjustment for finding noise for image": "Поправка к сигме подбора шума для рисунка",
+ "Loops": "Циклов",
+ "Denoising strength change factor": "Множитель силы шумоподавления",
+ "Recommended settings: Sampling Steps: 80-100, Sampler: Euler a, Denoising strength: 0.8": "Рекоммендуемые настройки: Число шагов:80-100,Метод:Euler a,Шумоподавление:0.8",
+ "Pixels to expand": "Пикселов расширить",
+ "Outpainting direction": "Направление обрисовывания",
+ "left": "влево",
+ "right": "вправо",
+ "up": "вверх",
+ "down": "вниз",
+ "Fall-off exponent (lower=higher detail)": "Степень затухания (меньше=больше деталей)",
+ "Color variation": "Вариация цвета",
+ "Will upscale the image to twice the dimensions; use width and height sliders to set tile size": "Расширит рисунок дважды; ползунки ширины и высоты устанавливают размеры плиток",
+ "Tile overlap": "Перекрытие плиток",
+ "Upscaler": "Апскейлер",
+ "Lanczos": "Lanczos",
+ "LDSR": "LDSR",
+ "BSRGAN 4x": "BSRGAN 4x",
+ "ESRGAN_4x": "ESRGAN_4x",
+ "R-ESRGAN 4x+ Anime6B": "R-ESRGAN 4x+ Anime6B",
+ "ScuNET GAN": "ScuNET GAN",
+ "ScuNET PSNR": "ScuNET PSNR",
+ "SwinIR_4x": "SwinIR 4x",
+ "Single Image": "Один рисунок",
+ "Batch Process": "Набор рисунков",
+ "Batch from Directory": "Рисунки из папки",
+ "Source": "Вход",
+ "Show result images": "Показать результаты",
+ "Scale by": "Увеличить в",
+ "Scale to": "Увеличить до",
+ "Resize": "Масштабировать",
+ "Crop to fit": "Обрезать до рамки",
+ "Upscaler 2": "Апскейлер 2",
+ "Upscaler 2 visibility": "Видимость Апскейлера 2",
+ "GFPGAN visibility": "Видимость GFPGAN",
+ "CodeFormer visibility": "Видимость CodeFormer",
+ "CodeFormer weight (0 = maximum effect, 1 = minimum effect)": "Вес CodeFormer (0 = максимальное действие, 1 = минимальное)",
+ "Open output directory": "Открыть папку выхода",
+ "Send to txt2img": "В текст-в-рисунок",
+ "txt2img history": "журнал текста-в-рисунок",
+ "img2img history": "журнал рисунка-в-рисунок",
+ "extras history": "журнал дополнений",
+ "Renew Page": "Обновить страницу",
+ "extras": "дополнения",
+ "favorites": "избранное",
+ "Load": "Загрузить",
+ "Images directory": "Папка с рисунками",
+ "Prev batch": "Пред. набор",
+ "Next batch": "След. набор",
+ "First Page": "Первая страница",
+ "Prev Page": "Пред. страница",
+ "Page Index": "Список страниц",
+ "Next Page": "След. страница",
+ "End Page": "Конец страницы",
+ "number of images to delete consecutively next": "сколько рисунков удалить подряд",
+ "Delete": "Удалить",
+ "Generate Info": "Сведения о генерации",
+ "File Name": "Имя файла",
+ "Collect": "Накопить",
+ "Refresh page": "Обновить страницу",
+ "Date to": "Дата",
+ "Number": "Число",
+ "set_index": "индекс",
+ "Checkbox": "Галочка",
+ "A merger of the two checkpoints will be generated in your": "Слияние весов будет создано, где хранятся",
+ "checkpoint": "ckpt",
+ "directory.": "веса",
+ "Primary model (A)": "Первичная модель (A)",
+ "Secondary model (B)": "Вторичная модель (B)",
+ "Tertiary model (C)": "Третичная модель (C)",
+ "Custom Name (Optional)": "Произвольное имя (необязательно)",
+ "Multiplier (M) - set to 0 to get model A": "Множитель (M) - 0 даст модель A",
+ "Interpolation Method": "Метод интерполяции",
+ "Weighted sum": "Взвешенная сумма",
+ "Add difference": "Сумма разностей",
+ "Save as float16": "Сохранить как float16",
+ "See": "См.",
+ "wiki": "вики",
+ "for detailed explanation.": "для подробных объяснений.",
+ "Create embedding": "Создать эмбеддинг",
+ "Create aesthetic images embedding": "Создать эмбеддинг эстетики по рисункам",
+ "Create hypernetwork": "Создать гиперсеть",
+ "Preprocess images": "Предобработать рисунки",
+ "Name": "Имя",
+ "Initialization text": "Соответствующий текст",
+ "Number of vectors per token": "Векторов на токен",
+ "Overwrite Old Embedding": "Перезаписать эмбеддинг",
+ "Source directory": "Исходная папка",
+ "Modules": "Модули",
+ "Enter hypernetwork layer structure": "Структура слоёв гиперсети",
+ "Add layer normalization": "Добавить нормализацию слоёв",
+ "Overwrite Old Hypernetwork": "Перезаписать гиперсеть",
+ "Select activation function of hypernetwork": "Функция активации гиперсети",
+ "linear": "линейная",
+ "relu": "relu",
+ "leakyrelu": "leakyrelu",
+ "Destination directory": "Папка назначения",
+ "Existing Caption txt Action": "Что делать с предыдущим текстом",
+ "ignore": "игнорировать",
+ "copy": "копировать",
+ "prepend": "в начало",
+ "append": "в конец",
+ "Create flipped copies": "Создать отражённые копии",
+ "Split oversized images into two": "Поделить слишком большие рисунки пополам",
+ "Split oversized images": "Поделить слишком большие рисунки",
+ "Use BLIP for caption": "Использовать BLIP для названий",
+ "Use deepbooru for caption": "Использовать deepbooru для тегов",
+ "Split image threshold": "Порог разделения рисунков",
+ "Split image overlap ratio": "Пропорции разделения рисунков",
+ "Preprocess": "Предобработка",
+ "Train an embedding; must specify a directory with a set of 1:1 ratio images": "Обучить эмбеддинг; укажите папку рисунков с пропорциями 1:1",
+ "Train an embedding or Hypernetwork; you must specify a directory with a set of 1:1 ratio images": "Обучить эмбеддинг или гиперсеть; укажите папку рисунков с пропорциями 1:1",
+ "[wiki]": "[вики]",
+ "Embedding": "Эмбеддинг",
+ "Embedding Learning rate": "Скорость обучения эмбеддинга",
+ "Hypernetwork Learning rate": "Скорость обучения гиперсети",
+ "Learning rate": "Скорость обучения",
+ "Dataset directory": "Папка датасета",
+ "Log directory": "Папка журнала",
+ "Prompt template file": "Файл шаблона запроса",
+ "Max steps": "Макс. шагов",
+ "Save an image to log directory every N steps, 0 to disable": "Сохранять рисунок каждые N шагов, 0 чтобы отключить",
+ "Save a copy of embedding to log directory every N steps, 0 to disable": "Сохранять эмбеддинг каждые N шагов, 0 чтобы отключить",
+ "Save images with embedding in PNG chunks": "Сохранить рисунок с эмбеддингом в виде PNG-фрагментов",
+ "Read parameters (prompt, etc...) from txt2img tab when making previews": "Считать параметры (запрос и т.д.) из вкладки текст-в-рисунок для предпросмотра",
+ "Train Hypernetwork": "Обучить гиперсеть",
+ "Train Embedding": "Обучить эмбеддинг",
+ "Create an aesthetic embedding out of any number of images": "Создать эмбеддинг эстетики по любому числу рисунков",
+ "Create images embedding": "Создать эмбеддинг рисунков",
+ "Apply settings": "Применить настройки",
+ "Saving images/grids": "Сохранение рисунков/таблиц",
+ "Always save all generated images": "Всегда сохранять созданные рисунки",
+ "File format for images": "Формат файла рисунков",
+ "Images filename pattern": "Формат имени файлов рисунков",
+ "Always save all generated image grids": "Всегда сохранять созданные таблицы",
+ "File format for grids": "Формат файла таблиц",
+ "Add extended info (seed, prompt) to filename when saving grid": "Вставлять доп. сведения (семя, запрос) в имя файла таблиц",
+ "Do not save grids consisting of one picture": "Не сохранять таблицы из одного рисунка",
+ "Prevent empty spots in grid (when set to autodetect)": "Не допускать пустоты в таблицах (автообнаружение)",
+ "Grid row count; use -1 for autodetect and 0 for it to be same as batch size": "Число строк таблицы; -1, чтобы автоматически, 0 — размер набора",
+ "Save text information about generation parameters as chunks to png files": "Встроить сведения о генерации в файлы png",
+ "Create a text file next to every image with generation parameters.": "Создать текстовый файл для каждого рисунка с параметрами генерации",
+ "Save a copy of image before doing face restoration.": "Сохранить копию перед восстановлением лиц",
+ "Quality for saved jpeg images": "Качество jpeg-рисунков",
+ "If PNG image is larger than 4MB or any dimension is larger than 4000, downscale and save copy as JPG": "Если размер PNG больше 4МБ или рисунок шире 4000 пикселей, пересжать в JPEG",
+ "Use original name for output filename during batch process in extras tab": "Использовать исходное имя выходного файла для обработки набора во вкладке дополнений",
+ "When using 'Save' button, only save a single selected image": "Сохранять только один рисунок при нажатии кнопки Сохранить",
+ "Do not add watermark to images": "Не добавлять водяной знак",
+ "Paths for saving": "Папки сохранений",
+ "Output directory for images; if empty, defaults to three directories below": "Папка выхода рисунков; если пусто, использует те, что ниже",
+ "Output directory for txt2img images": "Папка выхода текста-в-рисунок",
+ "Output directory for img2img images": "Папка выхода рисунка-в-рисунок",
+ "Output directory for images from extras tab": "Папка выхода для дополнений",
+ "Output directory for grids; if empty, defaults to two directories below": "Папка выхода таблиц; если пусто, использует папки выше",
+ "Output directory for txt2img grids": "Папка выхода текста-в-рисунок",
+ "Output directory for img2img grids": "Папка выхода рисунка-в-рисунок",
+ "Directory for saving images using the Save button": "Папка выхода для кнопки Сохранить",
+ "Saving to a directory": "Сохранить в папку",
+ "Save images to a subdirectory": "Сохранить рисунки в подпапку",
+ "Save grids to a subdirectory": "Сохранить таблицы в подпапку",
+ "When using \"Save\" button, save images to a subdirectory": "При нажатии кнопки Сохранить, сложить рисунки в подпапку",
+ "Directory name pattern": "Шаблон имени папки",
+ "Max prompt words for [prompt_words] pattern": "Макс. число слов для шаблона [prompt_words]",
+ "Upscaling": "Апскейл",
+ "Tile size for ESRGAN upscalers. 0 = no tiling.": "Размер плитки для ESRGAN. 0 = нет замощения",
+ "Tile overlap, in pixels for ESRGAN upscalers. Low values = visible seam.": "Наложение плиток ESRGAN, в пикселях. Меньше = выделеннее шов",
+ "Tile size for all SwinIR.": "Размер плиток SwinIR",
+ "Tile overlap, in pixels for SwinIR. Low values = visible seam.": "Наложение плиток SwinIR, в пикселях. Меньше = выделеннее шов",
+ "LDSR processing steps. Lower = faster": "Число шагов LDSR. Меньше = быстрее",
+ "Upscaler for img2img": "Апскейлер рисунка-в-рисунок",
+ "Upscale latent space image when doing hires. fix": "Апскейлить образ латентного пространства для HD-режима",
+ "Face restoration": "Восстановление лиц",
+ "CodeFormer weight parameter; 0 = maximum effect; 1 = minimum effect": "Вес CodeFormer; 0 = максимальное действие; 1 = минимальное",
+ "Move face restoration model from VRAM into RAM after processing": "Переместить модель восстановления лиц из ВОЗУ в ОЗУ после обработки",
+ "System": "Система",
+ "VRAM usage polls per second during generation. Set to 0 to disable.": "Сколько раз в секунду следить за потреблением ВОЗУ. 0, чтобы отключить",
+ "Always print all generation info to standard output": "Выводить все сведения о генерации в стандартный вывод",
+ "Add a second progress bar to the console that shows progress for an entire job.": "Вторая шкала прогресса для всей задачи",
+ "Training": "Обучение",
+ "Unload VAE and CLIP from VRAM when training": "Убрать VAE и CLIP из ВОЗУ на время обучения",
+ "Move VAE and CLIP to RAM when training hypernetwork. Saves VRAM.": "Переместить VAE и CLIP в ОЗУ на время обучения гиперсети. Сохраняет ВОЗУ",
+ "Filename word regex": "Regex имени файла",
+ "Filename join string": "Дополнить к имени файла",
+ "Number of repeats for a single input image per epoch; used only for displaying epoch number": "Число повторов для каждого рисунка за эпоху; используется только, чтобы отобразить число эпохи",
+ "Save an csv containing the loss to log directory every N steps, 0 to disable": "Сохранять csv с параметром loss в папку журнала каждые N шагов, 0 - отключить",
+ "Stable Diffusion": "Stable Diffusion",
+ "Checkpoints to cache in RAM": "Удерживать веса в ОЗУ",
+ "Hypernetwork strength": "Сила гиперсети",
+ "Apply color correction to img2img results to match original colors.": "Цветокоррекция вывода рисунка-в-рисунок, сохраняющая исходные цвета",
+ "Save a copy of image before applying color correction to img2img results": "Сохранить копию рисунка перед цветокоррекцией",
+ "With img2img, do exactly the amount of steps the slider specifies (normally you'd do less with less denoising).": "В режиме рисунок-в-рисунок сделать ровно указанное ползунком число шагов (обычно шумоподавление их уменьшает)",
+ "Enable quantization in K samplers for sharper and cleaner results. This may change existing seeds. Requires restart to apply.": "Включить квантование К-семплерах для более резких и чистых результатов. Может потребовать поменять семя. Требует перезапуска.",
+ "Emphasis: use (text) to make model pay more attention to text and [text] to make it pay less attention": "Скобки: (понятие) - больше внимания к тексту, [понятие] - меньше внимания к тексту",
+ "Use old emphasis implementation. Can be useful to reproduce old seeds.": "Включить старую обработку скобок. Может потребоваться, чтобы воспроизвести старые семена.",
+ "Make K-diffusion samplers produce same images in a batch as when making a single image": "Заставить семплеры K-diffusion производить тот же самый рисунок в наборе, как и в единичной генерации",
+ "Increase coherency by padding from the last comma within n tokens when using more than 75 tokens": "Увеличить связность, достраивая запрос от последней запятой до n токенов, когда используется свыше 75 токенов",
+ "Filter NSFW content": "Фильтровать небезопасный контент",
+ "Stop At last layers of CLIP model": "Остановиться на последних слоях модели CLIP",
+ "Interrogate Options": "Опции распознавания",
+ "Interrogate: keep models in VRAM": "Распознавание: хранить модели в ВОЗУ",
+ "Interrogate: use artists from artists.csv": "Распознавание: использовать художников из artists.csv",
+ "Interrogate: include ranks of model tags matches in results (Has no effect on caption-based interrogators).": "Распознавание: включить ранжирование совпавших тегов в результате (не работает для распознавателей-создателей заголовков)",
+ "Interrogate: num_beams for BLIP": "Распознавание: num_beams для BLIP",
+ "Interrogate: minimum description length (excluding artists, etc..)": "Распознавание: минимальная длина описания (исключая художников и т.п.)",
+ "Interrogate: maximum description length": "Распознавание: максимальная длина описания",
+ "CLIP: maximum number of lines in text file (0 = No limit)": "CLIP: максимальное число строк в текстовом файле (0 = без ограничений)",
+ "Interrogate: deepbooru score threshold": "Распознавание: ограничение счёта deepbooru",
+ "Interrogate: deepbooru sort alphabetically": "Распознавание: сортировать deepbooru по алфавиту",
+ "use spaces for tags in deepbooru": "Пробелы для тегов deepbooru",
+ "escape (\\) brackets in deepbooru (so they are used as literal brackets and not for emphasis)": "Использовать скобки в deepbooru как обычные скобки, а не для усиления",
+ "User interface": "Пользовательский интерфейс",
+ "Show progressbar": "Шкала прогресса",
+ "Show image creation progress every N sampling steps. Set 0 to disable.": "Показывать процесс созданния рисунка каждые N шагов. 0 - отключить",
+ "Show grid in results for web": "Показать таблицу в выводе браузера",
+ "Do not show any images in results for web": "Не показывать выходные рисунки в браузере",
+ "Add model hash to generation information": "Добавить хеш весов к параметрам генерации",
+ "Add model name to generation information": "Добавить имя весов к параметрам генерации",
+ "When reading generation parameters from text into UI (from PNG info or pasted text), do not change the selected model/checkpoint.": "При считывании параметров генерации из текста в интерфейс, не менять выбранную модель/веса.",
+ "Font for image grids that have text": "Шрифт для таблиц, содержащих текст",
+ "Enable full page image viewer": "Включить полноэкранный просмотр картинок",
+ "Show images zoomed in by default in full page image viewer": "По умолчанию увеличивать картинки в полноэкранном просмотре",
+ "Show generation progress in window title.": "Отображать прогресс в имени вкладки",
+ "Quicksettings list": "Список быстрых настроек",
+ "Localization (requires restart)": "Перевод (требует перезапуск)",
+ "Sampler parameters": "Параметры семплера",
+ "Hide samplers in user interface (requires restart)": "Убрать семплеры из интерфейса (требует перезапуск)",
+ "eta (noise multiplier) for DDIM": "eta (множитель шума) DDIM",
+ "eta (noise multiplier) for ancestral samplers": "eta (множитель шума) для ancestral-семплеров",
+ "img2img DDIM discretize": "дискретизация DDIM для рисунка-в-рисунок",
+ "uniform": "однородная",
+ "quad": "квадратичная",
+ "sigma churn": "сигма-вариация",
+ "sigma tmin": "сигма-tmin",
+ "sigma noise": "сигма-шум",
+ "Eta noise seed delta": "Eta (дельта шума семени)",
+ "Images Browser": "Просмотр изображений",
+ "Preload images at startup": "Предзагружать рисунки во время запуска",
+ "Number of pictures displayed on each page": "Число рисунков на каждой странице",
+ "Minimum number of pages per load": "Мин. число загружаемых страниц",
+ "Number of grids in each row": "Число таблиц в каждой строке",
+ "Request browser notifications": "Запросить уведомления браузера",
+ "Download localization template": "Загрузить щаблон перевода",
+ "Reload custom script bodies (No ui updates, No restart)": "Перезагрузить пользовательские скрипты (не требует обновления интерфейса и перезапуска)",
+ "Restart Gradio and Refresh components (Custom Scripts, ui.py, js and css only)": "Перезагрузить Gradio и обновить компоненты (только пользовательские скрипты, ui.py, js и css)",
+ "Prompt (press Ctrl+Enter or Alt+Enter to generate)": "Запрос (нажмите Ctrl+Enter или Alt+Enter для генерации)",
+ "Negative prompt (press Ctrl+Enter or Alt+Enter to generate)": "Запрос-исключение (нажмите Ctrl+Enter или Alt+Enter для генерации)",
+ "Add a random artist to the prompt.": "Добавить случайного художника к запросу",
+ "Read generation parameters from prompt or last generation if prompt is empty into user interface.": "Считать параметры генерации из запроса или из предыдущей генерации в пользовательский интерфейс, если пусто",
+ "Save style": "Сохранить стиль",
+ "Apply selected styles to current prompt": "Применить выбранные стили к текущему промпту",
+ "Stop processing current image and continue processing.": "Прекратить обрабатывать текущий рисунок, но продолжить работу",
+ "Stop processing images and return any results accumulated so far.": "Прекратить обрабатку рисунков и вернуть всё, что успели сделать.",
+ "Style to apply; styles have components for both positive and negative prompts and apply to both": "Стиль к применению; стили содержат как запрос, так и исключение, и применяют их оба",
+ "Do not do anything special": "Не делать ничего особенного",
+ "Which algorithm to use to produce the image": "Какой алгоритм использовать для того, чтобы произвести рисунок",
+ "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": "Euler Ancestral - очень творческий, в зависимости от числа шагов может привести совершенно к различным результатам, выше 30-40 лучше не ставить",
+ "Denoising Diffusion Implicit Models - best at inpainting": "Denoising Diffusion Implicit модели - лучше всего для обрисовки",
+ "Produce an image that can be tiled.": "Сделать из рисунка непрерывную обёртку",
+ "Use a two step process to partially create an image at smaller resolution, upscale, and then improve details in it without changing composition": "Применить двушаговый процесс, чтобы создать рисунок на меньшем разрешении, апскейлнуть, а затем улучшить детали без смены композиции",
+ "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.": "Определяет, насколько сильно алгоритм будет опираться на содержание изображения. 0 - не меняет ничего, 1 - совсем не связанный выход. Меньше 1.0 процесс использует меньше шагов, чем указано их ползунком.",
+ "How many batches of images to create": "Сколько создать наборов из картинок",
+ "How many image to create in a single batch": "Сколько картинок создать в каждом наборе",
+ "Classifier Free Guidance Scale - how strongly the image should conform to prompt - lower values produce more creative results": "Classifier Free Guidance Scale: насколько сильно изображение должно соответсвтовать запросу — меньшие значения приведут к более свободным итогам",
+ "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": "Значение, которое определяет выход генератора случайных чисел — если вы создадите рисунок с теми же параметрами и семенем, как у другого изображения, вы получите тот же результат",
+ "Set seed to -1, which will cause a new random number to be used every time": "Установить семя в -1, что вызовет каждый раз случайное число",
+ "Reuse seed from last generation, mostly useful if it was randomed": "Использовать семя предыдущей генерации, обычно полезно, если оно было случайным",
+ "Seed of a different picture to be mixed into the generation.": "Семя с другого рисунка, подмешенного в генерацию.",
+ "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).": "Насколько сильную вариацию произвести. При 0м значении действия не будет. Для 1 вы получите полноценный рисунок с семенем вариации (кроме ancestral-семплеров, где вы просто что-то получите).",
+ "Make an attempt to produce a picture similar to what would have been produced with same seed at specified resolution": "Попытаться воспроизвести изображение, похожее на то, чтобы получилось с тем же семенем на выбранном разрешении",
+ "This text is used to rotate the feature space of the imgs embs": "Этот текст используется, чтобы произвести вращение пространства признаков из эмбеддинга рисунков",
+ "Separate values for X axis using commas.": "Отдельные значения оси X через запятую.",
+ "Separate values for Y axis using commas.": "Отдельные значения оси Y через запятую.",
+ "Write image to a directory (default - log/images) and generation parameters into csv file.": "Записать изображение в папку (по-умолчанию - log/images), а параметры генерации - в csv файл",
+ "Open images output directory": "Открыть папку сохранения изображений",
+ "How much to blur the mask before processing, in pixels.": "Насколько пикселей размыть трафарет перед обработкой",
+ "What to put inside the masked area before processing it with Stable Diffusion.": "Что поместить в область под трафаретом перед обработкой Stable Diffusion",
+ "fill it with colors of the image": "залить цветами изображения",
+ "keep whatever was there originally": "сохранить то, что было до этого",
+ "fill it with latent space noise": "залить латентным шумом",
+ "fill it with latent space zeroes": "залить латентными нулями",
+ "Upscale masked region to target resolution, do inpainting, downscale back and paste into original image": "апскейл до нужного разрешения, врисовка, сжатие до начального размера и вставка в исходный рисунок",
+ "Resize image to target resolution. Unless height and width match, you will get incorrect aspect ratio.": "Масшабировать изображение до нужного разрешения. Если только высота и ширина не совпадают, вы получите неверное соотношение сторон.",
+ "Resize the image so that entirety of target resolution is filled with the image. Crop parts that stick out.": "Масштабировать изображение так, чтобы им заполнялось всё выбранное выходное разрешение. Обрезать выступающие части",
+ "Resize the image so that entirety of image is inside target resolution. Fill empty space with image's colors.": "Масштабировать изображение так, всё изображение помещалось в выбранное выходное разрешение. Заполнить пустое место цветами изображения.",
+ "How many times to repeat processing an image and using it as input for the next iteration": "Сколько раз повторить обработку изображения и использовать её как вход для следующией итерации",
+ "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.": "В режиме прокрутки, для каждого цикла сила шумоподавления умножается на это значение. <1 уменьшает вариации так, чтобы последовательность сошлась на какой-то одной картинке. >1 увеличивает вариации, так что ваша последовательность станет всё более и более сумбурной.",
+ "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.": "Для SD-апскейла, как много перекрытия в пикселях должно быть между плитками. Плитки перекрываются таким образом, чтобы они могли сойтись обратно в единое изображение, без видимого шва.",
+ "A directory on the same machine where the server is running.": "Папка на той же машине, где запущен сервер",
+ "Leave blank to save images to the default path.": "Оставьте пустым, чтобы сохранить рисунки в папку по-умолчанию",
+ "Result = A * (1 - M) + B * M": "Выход = A * (1 - M) + B * M",
+ "Result = A + (B - C) * M": "Выход = A + (B - C) * M",
+ "1st and last digit must be 1. ex:'1, 2, 1'": "1я и последняя цифры должны быть 1. напр.'1, 2, 1'",
+ "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.": "как быстро будет происходить обучение. Меньшие значения увеличат время обучения, но высокие могут нарушить сходимость модели (не будет создавать должные результаты) и/или сломать эмбеддинг. (Это случилось, если вы видете Loss: nan в текстовом окне вывода обучения. В этом случае вам придётся восстанавливать эмбеддинг вручную из старой, не повреждённой резервной копии).\n\nВы также можете указать единичное значение или последовательность из нескольких, используя следующий синтаксис:\n\n rate_1:max_steps_1, rate_2:max_steps_2, ...\n\nEG: 0.005:100, 1e-3:1000, 1e-5\n\nБудет обучаться со скоростью 0.005 первые 100 шагов, затем 1e-3 до 1000 шагов, после 1e-5 для всех оставшихся шагов.",
+ "Path to directory with input images": "Путь к папке со входными изображениями",
+ "Path to directory where to write outputs": "Путь к папке, в которую записывать результаты",
+ "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], [prompt_words], [date], [datetime], [job_timestamp]; leave empty for default.": "Используйте следующие теги, чтобы определить, как подбираются названия файлов для изображений: [steps], [cfg], [prompt], [prompt_no_styles], [prompt_spaces], [width], [height], [styles], [sampler], [seed], [model_hash], [prompt_words], [date], [datetime], [job_timestamp]; если пусто, используется значение по-умолчанию",
+ "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.": "Когда эта опция включена, на созданные изображения не будет добавляться водяной знак. Предупреждение: не добавляя водяной знак, вы, вероятно, ведёте себя аморально.",
+ "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], [prompt_words], [date], [datetime], [job_timestamp]; leave empty for default.": "Используйте следующие теги, чтобы определить, как подбираются названия подпапок для рисунков и табоиц: [steps], [cfg], [prompt], [prompt_no_styles], [prompt_spaces], [width], [height], [styles], [sampler], [seed], [model_hash], [prompt_words], [date], [datetime], [job_timestamp]; если пусто, используется значение по-умолчанию",
+ "Restore low quality faces using GFPGAN neural network": "Восстановить низкокачественные лица, используя нейросеть GFPGAN",
+ "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.": "Это регулярное выражение будет использовано, чтобы извлечь слова из имени файла, и они будут соединены с текстом в метке ниже как вход во время обучения. Оставьте пустым, чтобы сохранить имя файла как есть",
+ "This string will be used to join split words into a single line if the option above is enabled.": "Эта строка будет использована, чтобы объединить разделённые слова в одну строку, если включена опция выше.",
+ "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.": "Список имён настроек, разделённый запятыми, предназначенных для быстрого доступа через панель наверху, а не через привычную вкладку настроек. Для применения требует перезапуска.",
+ "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.": "Если это значение не нулевое, оно будет добавлено к семени и использовано для инициалицации ГСЧ шума семплеров с параметром Eta. Вы можете использовать это, чтобы произвести ещё больше вариаций рисунков, либо же для того, чтобы подойти близко к результатам других программ, если знаете, что делаете.",
+ "Enable Autocomplete": "Включить автодополнение",
+ "Allowed categories for random artists selection when using the Roll button": "Разрешённые категории художников для случайного выбора при использовании кнопки + три",
+ "Roll three": "+ три",
+ "Generate forever": "Непрерывная генерация",
+ "Cancel generate forever": "Отключить непрерывную генерацию"
+}
diff --git a/modules/api/api.py b/modules/api/api.py
index 5b0c934e..a860a964 100644
--- a/modules/api/api.py
+++ b/modules/api/api.py
@@ -1,5 +1,5 @@
-from modules.api.processing import StableDiffusionProcessingAPI
-from modules.processing import StableDiffusionProcessingTxt2Img, process_images
+from modules.api.models import StableDiffusionTxt2ImgProcessingAPI, StableDiffusionImg2ImgProcessingAPI
+from modules.processing import StableDiffusionProcessingTxt2Img, StableDiffusionProcessingImg2Img, process_images
from modules.sd_samplers import all_samplers
from modules.extras import run_pnginfo
import modules.shared as shared
@@ -10,6 +10,7 @@ from pydantic import BaseModel, Field, Json
import json
import io
import base64
+from PIL import Image
sampler_to_index = lambda name: next(filter(lambda row: name.lower() == row[1].name.lower(), enumerate(all_samplers)), None)
@@ -18,6 +19,11 @@ class TextToImageResponse(BaseModel):
parameters: Json
info: Json
+class ImageToImageResponse(BaseModel):
+ images: list[str] = Field(default=None, title="Image", description="The generated image in base64 format.")
+ parameters: Json
+ info: Json
+
class Api:
def __init__(self, app, queue_lock):
@@ -25,8 +31,17 @@ class Api:
self.app = app
self.queue_lock = queue_lock
self.app.add_api_route("/sdapi/v1/txt2img", self.text2imgapi, methods=["POST"])
+ self.app.add_api_route("/sdapi/v1/img2img", self.img2imgapi, methods=["POST"])
- def text2imgapi(self, txt2imgreq: StableDiffusionProcessingAPI ):
+ def __base64_to_image(self, base64_string):
+ # if has a comma, deal with prefix
+ if "," in base64_string:
+ base64_string = base64_string.split(",")[1]
+ imgdata = base64.b64decode(base64_string)
+ # convert base64 to PIL image
+ return Image.open(io.BytesIO(imgdata))
+
+ def text2imgapi(self, txt2imgreq: StableDiffusionTxt2ImgProcessingAPI):
sampler_index = sampler_to_index(txt2imgreq.sampler_index)
if sampler_index is None:
@@ -54,8 +69,49 @@ class Api:
- def img2imgapi(self):
- raise NotImplementedError
+ def img2imgapi(self, img2imgreq: StableDiffusionImg2ImgProcessingAPI):
+ sampler_index = sampler_to_index(img2imgreq.sampler_index)
+
+ if sampler_index is None:
+ raise HTTPException(status_code=404, detail="Sampler not found")
+
+
+ init_images = img2imgreq.init_images
+ if init_images is None:
+ raise HTTPException(status_code=404, detail="Init image not found")
+
+ mask = img2imgreq.mask
+ if mask:
+ mask = self.__base64_to_image(mask)
+
+
+ populate = img2imgreq.copy(update={ # Override __init__ params
+ "sd_model": shared.sd_model,
+ "sampler_index": sampler_index[0],
+ "do_not_save_samples": True,
+ "do_not_save_grid": True,
+ "mask": mask
+ }
+ )
+ p = StableDiffusionProcessingImg2Img(**vars(populate))
+
+ imgs = []
+ for img in init_images:
+ img = self.__base64_to_image(img)
+ imgs = [img] * p.batch_size
+
+ p.init_images = imgs
+ # Override object param
+ with self.queue_lock:
+ processed = process_images(p)
+
+ b64images = []
+ for i in processed.images:
+ buffer = io.BytesIO()
+ i.save(buffer, format="png")
+ b64images.append(base64.b64encode(buffer.getvalue()))
+
+ return ImageToImageResponse(images=b64images, parameters=json.dumps(vars(img2imgreq)), info=json.dumps(processed.info))
def extrasapi(self):
raise NotImplementedError
diff --git a/modules/api/processing.py b/modules/api/models.py
index 4c541241..f551fa35 100644
--- a/modules/api/processing.py
+++ b/modules/api/models.py
@@ -1,7 +1,8 @@
+from array import array
from inflection import underscore
from typing import Any, Dict, Optional
from pydantic import BaseModel, Field, create_model
-from modules.processing import StableDiffusionProcessingTxt2Img
+from modules.processing import StableDiffusionProcessingTxt2Img, StableDiffusionProcessingImg2Img
import inspect
@@ -92,8 +93,14 @@ class PydanticModelGenerator:
DynamicModel.__config__.allow_mutation = True
return DynamicModel
-StableDiffusionProcessingAPI = PydanticModelGenerator(
+StableDiffusionTxt2ImgProcessingAPI = PydanticModelGenerator(
"StableDiffusionProcessingTxt2Img",
StableDiffusionProcessingTxt2Img,
[{"key": "sampler_index", "type": str, "default": "Euler"}]
+).generate_model()
+
+StableDiffusionImg2ImgProcessingAPI = PydanticModelGenerator(
+ "StableDiffusionProcessingImg2Img",
+ StableDiffusionProcessingImg2Img,
+ [{"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}]
).generate_model() \ No newline at end of file
diff --git a/modules/bsrgan_model.py b/modules/bsrgan_model.py
deleted file mode 100644
index 737e1a76..00000000
--- a/modules/bsrgan_model.py
+++ /dev/null
@@ -1,76 +0,0 @@
-import os.path
-import sys
-import traceback
-
-import PIL.Image
-import numpy as np
-import torch
-from basicsr.utils.download_util import load_file_from_url
-
-import modules.upscaler
-from modules import devices, modelloader
-from modules.bsrgan_model_arch import RRDBNet
-
-
-class UpscalerBSRGAN(modules.upscaler.Upscaler):
- def __init__(self, dirname):
- self.name = "BSRGAN"
- self.model_name = "BSRGAN 4x"
- self.model_url = "https://github.com/cszn/KAIR/releases/download/v1.0/BSRGAN.pth"
- self.user_path = dirname
- super().__init__()
- model_paths = self.find_models(ext_filter=[".pt", ".pth"])
- scalers = []
- if len(model_paths) == 0:
- scaler_data = modules.upscaler.UpscalerData(self.model_name, self.model_url, self, 4)
- scalers.append(scaler_data)
- for file in model_paths:
- if "http" in file:
- name = self.model_name
- else:
- name = modelloader.friendly_name(file)
- try:
- scaler_data = modules.upscaler.UpscalerData(name, file, self, 4)
- scalers.append(scaler_data)
- except Exception:
- print(f"Error loading BSRGAN model: {file}", file=sys.stderr)
- print(traceback.format_exc(), file=sys.stderr)
- self.scalers = scalers
-
- def do_upscale(self, img: PIL.Image, selected_file):
- torch.cuda.empty_cache()
- model = self.load_model(selected_file)
- if model is None:
- return img
- model.to(devices.device_bsrgan)
- torch.cuda.empty_cache()
- img = np.array(img)
- img = img[:, :, ::-1]
- img = np.moveaxis(img, 2, 0) / 255
- img = torch.from_numpy(img).float()
- img = img.unsqueeze(0).to(devices.device_bsrgan)
- with torch.no_grad():
- output = model(img)
- output = output.squeeze().float().cpu().clamp_(0, 1).numpy()
- output = 255. * np.moveaxis(output, 0, 2)
- output = output.astype(np.uint8)
- output = output[:, :, ::-1]
- torch.cuda.empty_cache()
- return PIL.Image.fromarray(output, 'RGB')
-
- def load_model(self, path: str):
- if "http" in path:
- filename = load_file_from_url(url=self.model_url, model_dir=self.model_path, file_name="%s.pth" % self.name,
- progress=True)
- else:
- filename = path
- if not os.path.exists(filename) or filename is None:
- print(f"BSRGAN: Unable to load model from {filename}", file=sys.stderr)
- return None
- model = RRDBNet(in_nc=3, out_nc=3, nf=64, nb=23, gc=32, sf=4) # define network
- model.load_state_dict(torch.load(filename), strict=True)
- model.eval()
- for k, v in model.named_parameters():
- v.requires_grad = False
- return model
-
diff --git a/modules/bsrgan_model_arch.py b/modules/bsrgan_model_arch.py
deleted file mode 100644
index cb4d1c13..00000000
--- a/modules/bsrgan_model_arch.py
+++ /dev/null
@@ -1,102 +0,0 @@
-import functools
-import torch
-import torch.nn as nn
-import torch.nn.functional as F
-import torch.nn.init as init
-
-
-def initialize_weights(net_l, scale=1):
- if not isinstance(net_l, list):
- net_l = [net_l]
- for net in net_l:
- for m in net.modules():
- if isinstance(m, nn.Conv2d):
- init.kaiming_normal_(m.weight, a=0, mode='fan_in')
- m.weight.data *= scale # for residual block
- if m.bias is not None:
- m.bias.data.zero_()
- elif isinstance(m, nn.Linear):
- init.kaiming_normal_(m.weight, a=0, mode='fan_in')
- m.weight.data *= scale
- if m.bias is not None:
- m.bias.data.zero_()
- elif isinstance(m, nn.BatchNorm2d):
- init.constant_(m.weight, 1)
- init.constant_(m.bias.data, 0.0)
-
-
-def make_layer(block, n_layers):
- layers = []
- for _ in range(n_layers):
- layers.append(block())
- return nn.Sequential(*layers)
-
-
-class ResidualDenseBlock_5C(nn.Module):
- def __init__(self, nf=64, gc=32, bias=True):
- super(ResidualDenseBlock_5C, self).__init__()
- # gc: growth channel, i.e. intermediate channels
- self.conv1 = nn.Conv2d(nf, gc, 3, 1, 1, bias=bias)
- self.conv2 = nn.Conv2d(nf + gc, gc, 3, 1, 1, bias=bias)
- self.conv3 = nn.Conv2d(nf + 2 * gc, gc, 3, 1, 1, bias=bias)
- self.conv4 = nn.Conv2d(nf + 3 * gc, gc, 3, 1, 1, bias=bias)
- self.conv5 = nn.Conv2d(nf + 4 * gc, nf, 3, 1, 1, bias=bias)
- self.lrelu = nn.LeakyReLU(negative_slope=0.2, inplace=True)
-
- # initialization
- initialize_weights([self.conv1, self.conv2, self.conv3, self.conv4, self.conv5], 0.1)
-
- def forward(self, x):
- x1 = self.lrelu(self.conv1(x))
- x2 = self.lrelu(self.conv2(torch.cat((x, x1), 1)))
- x3 = self.lrelu(self.conv3(torch.cat((x, x1, x2), 1)))
- x4 = self.lrelu(self.conv4(torch.cat((x, x1, x2, x3), 1)))
- x5 = self.conv5(torch.cat((x, x1, x2, x3, x4), 1))
- return x5 * 0.2 + x
-
-
-class RRDB(nn.Module):
- '''Residual in Residual Dense Block'''
-
- def __init__(self, nf, gc=32):
- super(RRDB, self).__init__()
- self.RDB1 = ResidualDenseBlock_5C(nf, gc)
- self.RDB2 = ResidualDenseBlock_5C(nf, gc)
- self.RDB3 = ResidualDenseBlock_5C(nf, gc)
-
- def forward(self, x):
- out = self.RDB1(x)
- out = self.RDB2(out)
- out = self.RDB3(out)
- return out * 0.2 + x
-
-
-class RRDBNet(nn.Module):
- def __init__(self, in_nc=3, out_nc=3, nf=64, nb=23, gc=32, sf=4):
- super(RRDBNet, self).__init__()
- RRDB_block_f = functools.partial(RRDB, nf=nf, gc=gc)
- self.sf = sf
-
- self.conv_first = nn.Conv2d(in_nc, nf, 3, 1, 1, bias=True)
- self.RRDB_trunk = make_layer(RRDB_block_f, nb)
- self.trunk_conv = nn.Conv2d(nf, nf, 3, 1, 1, bias=True)
- #### upsampling
- self.upconv1 = nn.Conv2d(nf, nf, 3, 1, 1, bias=True)
- if self.sf==4:
- self.upconv2 = nn.Conv2d(nf, nf, 3, 1, 1, bias=True)
- self.HRconv = nn.Conv2d(nf, nf, 3, 1, 1, bias=True)
- self.conv_last = nn.Conv2d(nf, out_nc, 3, 1, 1, bias=True)
-
- self.lrelu = nn.LeakyReLU(negative_slope=0.2, inplace=True)
-
- def forward(self, x):
- fea = self.conv_first(x)
- trunk = self.trunk_conv(self.RRDB_trunk(fea))
- fea = fea + trunk
-
- fea = self.lrelu(self.upconv1(F.interpolate(fea, scale_factor=2, mode='nearest')))
- if self.sf==4:
- fea = self.lrelu(self.upconv2(F.interpolate(fea, scale_factor=2, mode='nearest')))
- out = self.conv_last(self.lrelu(self.HRconv(fea)))
-
- return out \ No newline at end of file
diff --git a/modules/deepbooru.py b/modules/deepbooru.py
index 8914662d..8bbc90a4 100644
--- a/modules/deepbooru.py
+++ b/modules/deepbooru.py
@@ -50,11 +50,12 @@ def create_deepbooru_process(threshold, deepbooru_opts):
the tags.
"""
from modules import shared # prevents circular reference
- shared.deepbooru_process_manager = multiprocessing.Manager()
+ context = multiprocessing.get_context("spawn")
+ shared.deepbooru_process_manager = context.Manager()
shared.deepbooru_process_queue = shared.deepbooru_process_manager.Queue()
shared.deepbooru_process_return = shared.deepbooru_process_manager.dict()
shared.deepbooru_process_return["value"] = -1
- shared.deepbooru_process = multiprocessing.Process(target=deepbooru_process, args=(shared.deepbooru_process_queue, shared.deepbooru_process_return, threshold, deepbooru_opts))
+ shared.deepbooru_process = context.Process(target=deepbooru_process, args=(shared.deepbooru_process_queue, shared.deepbooru_process_return, threshold, deepbooru_opts))
shared.deepbooru_process.start()
diff --git a/modules/devices.py b/modules/devices.py
index eb422583..7511e1dc 100644
--- a/modules/devices.py
+++ b/modules/devices.py
@@ -1,7 +1,6 @@
+import sys, os, shlex
import contextlib
-
import torch
-
from modules import errors
# has_mps is only available in nightly pytorch (for now), `getattr` for compatibility
@@ -9,10 +8,22 @@ has_mps = getattr(torch, 'has_mps', False)
cpu = torch.device("cpu")
+def extract_device_id(args, name):
+ for x in range(len(args)):
+ if name in args[x]: return args[x+1]
+ return None
def get_optimal_device():
if torch.cuda.is_available():
- return torch.device("cuda")
+ from modules import shared
+
+ device_id = shared.cmd_opts.device_id
+
+ if device_id is not None:
+ cuda_device = f"cuda:{device_id}"
+ return torch.device(cuda_device)
+ else:
+ return torch.device("cuda")
if has_mps:
return torch.device("mps")
@@ -34,7 +45,7 @@ def enable_tf32():
errors.run(enable_tf32, "Enabling TF32")
-device = device_interrogate = device_gfpgan = device_bsrgan = device_esrgan = device_scunet = device_codeformer = get_optimal_device()
+device = device_interrogate = device_gfpgan = device_swinir = device_esrgan = device_scunet = device_codeformer = None
dtype = torch.float16
dtype_vae = torch.float16
@@ -70,3 +81,7 @@ def autocast(disable=False):
return contextlib.nullcontext()
return torch.autocast("cuda")
+
+# MPS workaround for https://github.com/pytorch/pytorch/issues/79383
+def mps_contiguous(input_tensor, device): return input_tensor.contiguous() if device.type == 'mps' else input_tensor
+def mps_contiguous_to(input_tensor, device): return mps_contiguous(input_tensor, device).to(device)
diff --git a/modules/esrgan_model.py b/modules/esrgan_model.py
index 46ad0da3..a13cf6ac 100644
--- a/modules/esrgan_model.py
+++ b/modules/esrgan_model.py
@@ -11,62 +11,109 @@ from modules.upscaler import Upscaler, UpscalerData
from modules.shared import opts
-def fix_model_layers(crt_model, pretrained_net):
- # this code is adapted from https://github.com/xinntao/ESRGAN
- if 'conv_first.weight' in pretrained_net:
- return pretrained_net
-
- if 'model.0.weight' not in pretrained_net:
- is_realesrgan = "params_ema" in pretrained_net and 'body.0.rdb1.conv1.weight' in pretrained_net["params_ema"]
- if is_realesrgan:
- raise Exception("The file is a RealESRGAN model, it can't be used as a ESRGAN model.")
- else:
- raise Exception("The file is not a ESRGAN model.")
- crt_net = crt_model.state_dict()
- load_net_clean = {}
- for k, v in pretrained_net.items():
- if k.startswith('module.'):
- load_net_clean[k[7:]] = v
- else:
- load_net_clean[k] = v
- pretrained_net = load_net_clean
-
- tbd = []
- for k, v in crt_net.items():
- tbd.append(k)
-
- # directly copy
- for k, v in crt_net.items():
- if k in pretrained_net and pretrained_net[k].size() == v.size():
- crt_net[k] = pretrained_net[k]
- tbd.remove(k)
-
- crt_net['conv_first.weight'] = pretrained_net['model.0.weight']
- crt_net['conv_first.bias'] = pretrained_net['model.0.bias']
-
- for k in tbd.copy():
- if 'RDB' in k:
- ori_k = k.replace('RRDB_trunk.', 'model.1.sub.')
- if '.weight' in k:
- ori_k = ori_k.replace('.weight', '.0.weight')
- elif '.bias' in k:
- ori_k = ori_k.replace('.bias', '.0.bias')
- crt_net[k] = pretrained_net[ori_k]
- tbd.remove(k)
-
- crt_net['trunk_conv.weight'] = pretrained_net['model.1.sub.23.weight']
- crt_net['trunk_conv.bias'] = pretrained_net['model.1.sub.23.bias']
- crt_net['upconv1.weight'] = pretrained_net['model.3.weight']
- crt_net['upconv1.bias'] = pretrained_net['model.3.bias']
- crt_net['upconv2.weight'] = pretrained_net['model.6.weight']
- crt_net['upconv2.bias'] = pretrained_net['model.6.bias']
- crt_net['HRconv.weight'] = pretrained_net['model.8.weight']
- crt_net['HRconv.bias'] = pretrained_net['model.8.bias']
- crt_net['conv_last.weight'] = pretrained_net['model.10.weight']
- crt_net['conv_last.bias'] = pretrained_net['model.10.bias']
-
- return crt_net
+def mod2normal(state_dict):
+ # this code is copied from https://github.com/victorca25/iNNfer
+ if 'conv_first.weight' in state_dict:
+ crt_net = {}
+ items = []
+ for k, v in state_dict.items():
+ items.append(k)
+
+ crt_net['model.0.weight'] = state_dict['conv_first.weight']
+ crt_net['model.0.bias'] = state_dict['conv_first.bias']
+
+ for k in items.copy():
+ if 'RDB' in k:
+ ori_k = k.replace('RRDB_trunk.', 'model.1.sub.')
+ if '.weight' in k:
+ ori_k = ori_k.replace('.weight', '.0.weight')
+ elif '.bias' in k:
+ ori_k = ori_k.replace('.bias', '.0.bias')
+ crt_net[ori_k] = state_dict[k]
+ items.remove(k)
+
+ crt_net['model.1.sub.23.weight'] = state_dict['trunk_conv.weight']
+ crt_net['model.1.sub.23.bias'] = state_dict['trunk_conv.bias']
+ crt_net['model.3.weight'] = state_dict['upconv1.weight']
+ crt_net['model.3.bias'] = state_dict['upconv1.bias']
+ crt_net['model.6.weight'] = state_dict['upconv2.weight']
+ crt_net['model.6.bias'] = state_dict['upconv2.bias']
+ crt_net['model.8.weight'] = state_dict['HRconv.weight']
+ crt_net['model.8.bias'] = state_dict['HRconv.bias']
+ crt_net['model.10.weight'] = state_dict['conv_last.weight']
+ crt_net['model.10.bias'] = state_dict['conv_last.bias']
+ state_dict = crt_net
+ return state_dict
+
+
+def resrgan2normal(state_dict, nb=23):
+ # this code is copied from https://github.com/victorca25/iNNfer
+ if "conv_first.weight" in state_dict and "body.0.rdb1.conv1.weight" in state_dict:
+ crt_net = {}
+ items = []
+ for k, v in state_dict.items():
+ items.append(k)
+
+ crt_net['model.0.weight'] = state_dict['conv_first.weight']
+ crt_net['model.0.bias'] = state_dict['conv_first.bias']
+
+ for k in items.copy():
+ if "rdb" in k:
+ ori_k = k.replace('body.', 'model.1.sub.')
+ ori_k = ori_k.replace('.rdb', '.RDB')
+ if '.weight' in k:
+ ori_k = ori_k.replace('.weight', '.0.weight')
+ elif '.bias' in k:
+ ori_k = ori_k.replace('.bias', '.0.bias')
+ crt_net[ori_k] = state_dict[k]
+ items.remove(k)
+
+ crt_net[f'model.1.sub.{nb}.weight'] = state_dict['conv_body.weight']
+ crt_net[f'model.1.sub.{nb}.bias'] = state_dict['conv_body.bias']
+ crt_net['model.3.weight'] = state_dict['conv_up1.weight']
+ crt_net['model.3.bias'] = state_dict['conv_up1.bias']
+ crt_net['model.6.weight'] = state_dict['conv_up2.weight']
+ crt_net['model.6.bias'] = state_dict['conv_up2.bias']
+ crt_net['model.8.weight'] = state_dict['conv_hr.weight']
+ crt_net['model.8.bias'] = state_dict['conv_hr.bias']
+ crt_net['model.10.weight'] = state_dict['conv_last.weight']
+ crt_net['model.10.bias'] = state_dict['conv_last.bias']
+ state_dict = crt_net
+ return state_dict
+
+
+def infer_params(state_dict):
+ # this code is copied from https://github.com/victorca25/iNNfer
+ scale2x = 0
+ scalemin = 6
+ n_uplayer = 0
+ plus = False
+
+ for block in list(state_dict):
+ parts = block.split(".")
+ n_parts = len(parts)
+ if n_parts == 5 and parts[2] == "sub":
+ nb = int(parts[3])
+ elif n_parts == 3:
+ part_num = int(parts[1])
+ if (part_num > scalemin
+ and parts[0] == "model"
+ and parts[2] == "weight"):
+ scale2x += 1
+ if part_num > n_uplayer:
+ n_uplayer = part_num
+ out_nc = state_dict[block].shape[0]
+ if not plus and "conv1x1" in block:
+ plus = True
+
+ nf = state_dict["model.0.weight"].shape[0]
+ in_nc = state_dict["model.0.weight"].shape[1]
+ out_nc = out_nc
+ scale = 2 ** scale2x
+
+ return in_nc, out_nc, nf, nb, plus, scale
+
class UpscalerESRGAN(Upscaler):
def __init__(self, dirname):
@@ -109,22 +156,41 @@ class UpscalerESRGAN(Upscaler):
print("Unable to load %s from %s" % (self.model_path, filename))
return None
- pretrained_net = torch.load(filename, map_location='cpu' if devices.device_esrgan.type == 'mps' else None)
- crt_model = arch.RRDBNet(3, 3, 64, 23, gc=32)
+ state_dict = torch.load(filename, map_location='cpu' if devices.device_esrgan.type == 'mps' else None)
+
+ if "params_ema" in state_dict:
+ state_dict = state_dict["params_ema"]
+ elif "params" in state_dict:
+ state_dict = state_dict["params"]
+ num_conv = 16 if "realesr-animevideov3" in filename else 32
+ model = arch.SRVGGNetCompact(num_in_ch=3, num_out_ch=3, num_feat=64, num_conv=num_conv, upscale=4, act_type='prelu')
+ model.load_state_dict(state_dict)
+ model.eval()
+ return model
+
+ if "body.0.rdb1.conv1.weight" in state_dict and "conv_first.weight" in state_dict:
+ nb = 6 if "RealESRGAN_x4plus_anime_6B" in filename else 23
+ state_dict = resrgan2normal(state_dict, nb)
+ elif "conv_first.weight" in state_dict:
+ state_dict = mod2normal(state_dict)
+ elif "model.0.weight" not in state_dict:
+ raise Exception("The file is not a recognized ESRGAN model.")
+
+ in_nc, out_nc, nf, nb, plus, mscale = infer_params(state_dict)
- pretrained_net = fix_model_layers(crt_model, pretrained_net)
- crt_model.load_state_dict(pretrained_net)
- crt_model.eval()
+ model = arch.RRDBNet(in_nc=in_nc, out_nc=out_nc, nf=nf, nb=nb, upscale=mscale, plus=plus)
+ model.load_state_dict(state_dict)
+ model.eval()
- return crt_model
+ return model
def upscale_without_tiling(model, img):
img = np.array(img)
img = img[:, :, ::-1]
- img = np.moveaxis(img, 2, 0) / 255
+ img = np.ascontiguousarray(np.transpose(img, (2, 0, 1))) / 255
img = torch.from_numpy(img).float()
- img = img.unsqueeze(0).to(devices.device_esrgan)
+ img = devices.mps_contiguous_to(img.unsqueeze(0), devices.device_esrgan)
with torch.no_grad():
output = model(img)
output = output.squeeze().float().cpu().clamp_(0, 1).numpy()
diff --git a/modules/esrgan_model_arch.py b/modules/esrgan_model_arch.py
index e413d36e..bc9ceb2a 100644
--- a/modules/esrgan_model_arch.py
+++ b/modules/esrgan_model_arch.py
@@ -1,80 +1,463 @@
-# this file is taken from https://github.com/xinntao/ESRGAN
+# this file is adapted from https://github.com/victorca25/iNNfer
+import math
import functools
import torch
import torch.nn as nn
import torch.nn.functional as F
-def make_layer(block, n_layers):
- layers = []
- for _ in range(n_layers):
- layers.append(block())
- return nn.Sequential(*layers)
+####################
+# RRDBNet Generator
+####################
+class RRDBNet(nn.Module):
+ def __init__(self, in_nc, out_nc, nf, nb, nr=3, gc=32, upscale=4, norm_type=None,
+ act_type='leakyrelu', mode='CNA', upsample_mode='upconv', convtype='Conv2D',
+ finalact=None, gaussian_noise=False, plus=False):
+ super(RRDBNet, self).__init__()
+ n_upscale = int(math.log(upscale, 2))
+ if upscale == 3:
+ n_upscale = 1
-class ResidualDenseBlock_5C(nn.Module):
- def __init__(self, nf=64, gc=32, bias=True):
- super(ResidualDenseBlock_5C, self).__init__()
- # gc: growth channel, i.e. intermediate channels
- self.conv1 = nn.Conv2d(nf, gc, 3, 1, 1, bias=bias)
- self.conv2 = nn.Conv2d(nf + gc, gc, 3, 1, 1, bias=bias)
- self.conv3 = nn.Conv2d(nf + 2 * gc, gc, 3, 1, 1, bias=bias)
- self.conv4 = nn.Conv2d(nf + 3 * gc, gc, 3, 1, 1, bias=bias)
- self.conv5 = nn.Conv2d(nf + 4 * gc, nf, 3, 1, 1, bias=bias)
- self.lrelu = nn.LeakyReLU(negative_slope=0.2, inplace=True)
+ self.resrgan_scale = 0
+ if in_nc % 16 == 0:
+ self.resrgan_scale = 1
+ elif in_nc != 4 and in_nc % 4 == 0:
+ self.resrgan_scale = 2
- # initialization
- # mutil.initialize_weights([self.conv1, self.conv2, self.conv3, self.conv4, self.conv5], 0.1)
+ fea_conv = conv_block(in_nc, nf, kernel_size=3, norm_type=None, act_type=None, convtype=convtype)
+ rb_blocks = [RRDB(nf, nr, kernel_size=3, gc=32, stride=1, bias=1, pad_type='zero',
+ norm_type=norm_type, act_type=act_type, mode='CNA', convtype=convtype,
+ gaussian_noise=gaussian_noise, plus=plus) for _ in range(nb)]
+ LR_conv = conv_block(nf, nf, kernel_size=3, norm_type=norm_type, act_type=None, mode=mode, convtype=convtype)
- def forward(self, x):
- x1 = self.lrelu(self.conv1(x))
- x2 = self.lrelu(self.conv2(torch.cat((x, x1), 1)))
- x3 = self.lrelu(self.conv3(torch.cat((x, x1, x2), 1)))
- x4 = self.lrelu(self.conv4(torch.cat((x, x1, x2, x3), 1)))
- x5 = self.conv5(torch.cat((x, x1, x2, x3, x4), 1))
- return x5 * 0.2 + x
+ if upsample_mode == 'upconv':
+ upsample_block = upconv_block
+ elif upsample_mode == 'pixelshuffle':
+ upsample_block = pixelshuffle_block
+ else:
+ raise NotImplementedError('upsample mode [{:s}] is not found'.format(upsample_mode))
+ if upscale == 3:
+ upsampler = upsample_block(nf, nf, 3, act_type=act_type, convtype=convtype)
+ else:
+ upsampler = [upsample_block(nf, nf, act_type=act_type, convtype=convtype) for _ in range(n_upscale)]
+ HR_conv0 = conv_block(nf, nf, kernel_size=3, norm_type=None, act_type=act_type, convtype=convtype)
+ HR_conv1 = conv_block(nf, out_nc, kernel_size=3, norm_type=None, act_type=None, convtype=convtype)
+
+ outact = act(finalact) if finalact else None
+
+ self.model = sequential(fea_conv, ShortcutBlock(sequential(*rb_blocks, LR_conv)),
+ *upsampler, HR_conv0, HR_conv1, outact)
+
+ def forward(self, x, outm=None):
+ if self.resrgan_scale == 1:
+ feat = pixel_unshuffle(x, scale=4)
+ elif self.resrgan_scale == 2:
+ feat = pixel_unshuffle(x, scale=2)
+ else:
+ feat = x
+
+ return self.model(feat)
class RRDB(nn.Module):
- '''Residual in Residual Dense Block'''
+ """
+ Residual in Residual Dense Block
+ (ESRGAN: Enhanced Super-Resolution Generative Adversarial Networks)
+ """
- def __init__(self, nf, gc=32):
+ def __init__(self, nf, nr=3, kernel_size=3, gc=32, stride=1, bias=1, pad_type='zero',
+ norm_type=None, act_type='leakyrelu', mode='CNA', convtype='Conv2D',
+ spectral_norm=False, gaussian_noise=False, plus=False):
super(RRDB, self).__init__()
- self.RDB1 = ResidualDenseBlock_5C(nf, gc)
- self.RDB2 = ResidualDenseBlock_5C(nf, gc)
- self.RDB3 = ResidualDenseBlock_5C(nf, gc)
+ # This is for backwards compatibility with existing models
+ if nr == 3:
+ self.RDB1 = ResidualDenseBlock_5C(nf, kernel_size, gc, stride, bias, pad_type,
+ norm_type, act_type, mode, convtype, spectral_norm=spectral_norm,
+ gaussian_noise=gaussian_noise, plus=plus)
+ self.RDB2 = ResidualDenseBlock_5C(nf, kernel_size, gc, stride, bias, pad_type,
+ norm_type, act_type, mode, convtype, spectral_norm=spectral_norm,
+ gaussian_noise=gaussian_noise, plus=plus)
+ self.RDB3 = ResidualDenseBlock_5C(nf, kernel_size, gc, stride, bias, pad_type,
+ norm_type, act_type, mode, convtype, spectral_norm=spectral_norm,
+ gaussian_noise=gaussian_noise, plus=plus)
+ else:
+ RDB_list = [ResidualDenseBlock_5C(nf, kernel_size, gc, stride, bias, pad_type,
+ norm_type, act_type, mode, convtype, spectral_norm=spectral_norm,
+ gaussian_noise=gaussian_noise, plus=plus) for _ in range(nr)]
+ self.RDBs = nn.Sequential(*RDB_list)
def forward(self, x):
- out = self.RDB1(x)
- out = self.RDB2(out)
- out = self.RDB3(out)
+ if hasattr(self, 'RDB1'):
+ out = self.RDB1(x)
+ out = self.RDB2(out)
+ out = self.RDB3(out)
+ else:
+ out = self.RDBs(x)
return out * 0.2 + x
-class RRDBNet(nn.Module):
- def __init__(self, in_nc, out_nc, nf, nb, gc=32):
- super(RRDBNet, self).__init__()
- RRDB_block_f = functools.partial(RRDB, nf=nf, gc=gc)
+class ResidualDenseBlock_5C(nn.Module):
+ """
+ Residual Dense Block
+ The core module of paper: (Residual Dense Network for Image Super-Resolution, CVPR 18)
+ Modified options that can be used:
+ - "Partial Convolution based Padding" arXiv:1811.11718
+ - "Spectral normalization" arXiv:1802.05957
+ - "ICASSP 2020 - ESRGAN+ : Further Improving ESRGAN" N. C.
+ {Rakotonirina} and A. {Rasoanaivo}
+ """
+
+ def __init__(self, nf=64, kernel_size=3, gc=32, stride=1, bias=1, pad_type='zero',
+ norm_type=None, act_type='leakyrelu', mode='CNA', convtype='Conv2D',
+ spectral_norm=False, gaussian_noise=False, plus=False):
+ super(ResidualDenseBlock_5C, self).__init__()
- self.conv_first = nn.Conv2d(in_nc, nf, 3, 1, 1, bias=True)
- self.RRDB_trunk = make_layer(RRDB_block_f, nb)
- self.trunk_conv = nn.Conv2d(nf, nf, 3, 1, 1, bias=True)
- #### upsampling
- self.upconv1 = nn.Conv2d(nf, nf, 3, 1, 1, bias=True)
- self.upconv2 = nn.Conv2d(nf, nf, 3, 1, 1, bias=True)
- self.HRconv = nn.Conv2d(nf, nf, 3, 1, 1, bias=True)
- self.conv_last = nn.Conv2d(nf, out_nc, 3, 1, 1, bias=True)
+ self.noise = GaussianNoise() if gaussian_noise else None
+ self.conv1x1 = conv1x1(nf, gc) if plus else None
- self.lrelu = nn.LeakyReLU(negative_slope=0.2, inplace=True)
+ self.conv1 = conv_block(nf, gc, kernel_size, stride, bias=bias, pad_type=pad_type,
+ norm_type=norm_type, act_type=act_type, mode=mode, convtype=convtype,
+ spectral_norm=spectral_norm)
+ self.conv2 = conv_block(nf+gc, gc, kernel_size, stride, bias=bias, pad_type=pad_type,
+ norm_type=norm_type, act_type=act_type, mode=mode, convtype=convtype,
+ spectral_norm=spectral_norm)
+ self.conv3 = conv_block(nf+2*gc, gc, kernel_size, stride, bias=bias, pad_type=pad_type,
+ norm_type=norm_type, act_type=act_type, mode=mode, convtype=convtype,
+ spectral_norm=spectral_norm)
+ self.conv4 = conv_block(nf+3*gc, gc, kernel_size, stride, bias=bias, pad_type=pad_type,
+ norm_type=norm_type, act_type=act_type, mode=mode, convtype=convtype,
+ spectral_norm=spectral_norm)
+ if mode == 'CNA':
+ last_act = None
+ else:
+ last_act = act_type
+ self.conv5 = conv_block(nf+4*gc, nf, 3, stride, bias=bias, pad_type=pad_type,
+ norm_type=norm_type, act_type=last_act, mode=mode, convtype=convtype,
+ spectral_norm=spectral_norm)
def forward(self, x):
- fea = self.conv_first(x)
- trunk = self.trunk_conv(self.RRDB_trunk(fea))
- fea = fea + trunk
+ x1 = self.conv1(x)
+ x2 = self.conv2(torch.cat((x, x1), 1))
+ if self.conv1x1:
+ x2 = x2 + self.conv1x1(x)
+ x3 = self.conv3(torch.cat((x, x1, x2), 1))
+ x4 = self.conv4(torch.cat((x, x1, x2, x3), 1))
+ if self.conv1x1:
+ x4 = x4 + x2
+ x5 = self.conv5(torch.cat((x, x1, x2, x3, x4), 1))
+ if self.noise:
+ return self.noise(x5.mul(0.2) + x)
+ else:
+ return x5 * 0.2 + x
+
- fea = self.lrelu(self.upconv1(F.interpolate(fea, scale_factor=2, mode='nearest')))
- fea = self.lrelu(self.upconv2(F.interpolate(fea, scale_factor=2, mode='nearest')))
- out = self.conv_last(self.lrelu(self.HRconv(fea)))
+####################
+# ESRGANplus
+####################
+class GaussianNoise(nn.Module):
+ def __init__(self, sigma=0.1, is_relative_detach=False):
+ super().__init__()
+ self.sigma = sigma
+ self.is_relative_detach = is_relative_detach
+ self.noise = torch.tensor(0, dtype=torch.float)
+
+ def forward(self, x):
+ if self.training and self.sigma != 0:
+ self.noise = self.noise.to(x.device)
+ scale = self.sigma * x.detach() if self.is_relative_detach else self.sigma * x
+ sampled_noise = self.noise.repeat(*x.size()).normal_() * scale
+ x = x + sampled_noise
+ return x
+
+def conv1x1(in_planes, out_planes, stride=1):
+ return nn.Conv2d(in_planes, out_planes, kernel_size=1, stride=stride, bias=False)
+
+
+####################
+# SRVGGNetCompact
+####################
+
+class SRVGGNetCompact(nn.Module):
+ """A compact VGG-style network structure for super-resolution.
+ This class is copied from https://github.com/xinntao/Real-ESRGAN
+ """
+
+ def __init__(self, num_in_ch=3, num_out_ch=3, num_feat=64, num_conv=16, upscale=4, act_type='prelu'):
+ super(SRVGGNetCompact, self).__init__()
+ self.num_in_ch = num_in_ch
+ self.num_out_ch = num_out_ch
+ self.num_feat = num_feat
+ self.num_conv = num_conv
+ self.upscale = upscale
+ self.act_type = act_type
+
+ self.body = nn.ModuleList()
+ # the first conv
+ self.body.append(nn.Conv2d(num_in_ch, num_feat, 3, 1, 1))
+ # the first activation
+ if act_type == 'relu':
+ activation = nn.ReLU(inplace=True)
+ elif act_type == 'prelu':
+ activation = nn.PReLU(num_parameters=num_feat)
+ elif act_type == 'leakyrelu':
+ activation = nn.LeakyReLU(negative_slope=0.1, inplace=True)
+ self.body.append(activation)
+
+ # the body structure
+ for _ in range(num_conv):
+ self.body.append(nn.Conv2d(num_feat, num_feat, 3, 1, 1))
+ # activation
+ if act_type == 'relu':
+ activation = nn.ReLU(inplace=True)
+ elif act_type == 'prelu':
+ activation = nn.PReLU(num_parameters=num_feat)
+ elif act_type == 'leakyrelu':
+ activation = nn.LeakyReLU(negative_slope=0.1, inplace=True)
+ self.body.append(activation)
+
+ # the last conv
+ self.body.append(nn.Conv2d(num_feat, num_out_ch * upscale * upscale, 3, 1, 1))
+ # upsample
+ self.upsampler = nn.PixelShuffle(upscale)
+
+ def forward(self, x):
+ out = x
+ for i in range(0, len(self.body)):
+ out = self.body[i](out)
+
+ out = self.upsampler(out)
+ # add the nearest upsampled image, so that the network learns the residual
+ base = F.interpolate(x, scale_factor=self.upscale, mode='nearest')
+ out += base
return out
+
+
+####################
+# Upsampler
+####################
+
+class Upsample(nn.Module):
+ r"""Upsamples a given multi-channel 1D (temporal), 2D (spatial) or 3D (volumetric) data.
+ The input data is assumed to be of the form
+ `minibatch x channels x [optional depth] x [optional height] x width`.
+ """
+
+ def __init__(self, size=None, scale_factor=None, mode="nearest", align_corners=None):
+ super(Upsample, self).__init__()
+ if isinstance(scale_factor, tuple):
+ self.scale_factor = tuple(float(factor) for factor in scale_factor)
+ else:
+ self.scale_factor = float(scale_factor) if scale_factor else None
+ self.mode = mode
+ self.size = size
+ self.align_corners = align_corners
+
+ def forward(self, x):
+ return nn.functional.interpolate(x, size=self.size, scale_factor=self.scale_factor, mode=self.mode, align_corners=self.align_corners)
+
+ def extra_repr(self):
+ if self.scale_factor is not None:
+ info = 'scale_factor=' + str(self.scale_factor)
+ else:
+ info = 'size=' + str(self.size)
+ info += ', mode=' + self.mode
+ return info
+
+
+def pixel_unshuffle(x, scale):
+ """ Pixel unshuffle.
+ Args:
+ x (Tensor): Input feature with shape (b, c, hh, hw).
+ scale (int): Downsample ratio.
+ Returns:
+ Tensor: the pixel unshuffled feature.
+ """
+ b, c, hh, hw = x.size()
+ out_channel = c * (scale**2)
+ assert hh % scale == 0 and hw % scale == 0
+ h = hh // scale
+ w = hw // scale
+ x_view = x.view(b, c, h, scale, w, scale)
+ return x_view.permute(0, 1, 3, 5, 2, 4).reshape(b, out_channel, h, w)
+
+
+def pixelshuffle_block(in_nc, out_nc, upscale_factor=2, kernel_size=3, stride=1, bias=True,
+ pad_type='zero', norm_type=None, act_type='relu', convtype='Conv2D'):
+ """
+ Pixel shuffle layer
+ (Real-Time Single Image and Video Super-Resolution Using an Efficient Sub-Pixel Convolutional
+ Neural Network, CVPR17)
+ """
+ conv = conv_block(in_nc, out_nc * (upscale_factor ** 2), kernel_size, stride, bias=bias,
+ pad_type=pad_type, norm_type=None, act_type=None, convtype=convtype)
+ pixel_shuffle = nn.PixelShuffle(upscale_factor)
+
+ n = norm(norm_type, out_nc) if norm_type else None
+ a = act(act_type) if act_type else None
+ return sequential(conv, pixel_shuffle, n, a)
+
+
+def upconv_block(in_nc, out_nc, upscale_factor=2, kernel_size=3, stride=1, bias=True,
+ pad_type='zero', norm_type=None, act_type='relu', mode='nearest', convtype='Conv2D'):
+ """ Upconv layer """
+ upscale_factor = (1, upscale_factor, upscale_factor) if convtype == 'Conv3D' else upscale_factor
+ upsample = Upsample(scale_factor=upscale_factor, mode=mode)
+ conv = conv_block(in_nc, out_nc, kernel_size, stride, bias=bias,
+ pad_type=pad_type, norm_type=norm_type, act_type=act_type, convtype=convtype)
+ return sequential(upsample, conv)
+
+
+
+
+
+
+
+
+####################
+# Basic blocks
+####################
+
+
+def make_layer(basic_block, num_basic_block, **kwarg):
+ """Make layers by stacking the same blocks.
+ Args:
+ basic_block (nn.module): nn.module class for basic block. (block)
+ num_basic_block (int): number of blocks. (n_layers)
+ Returns:
+ nn.Sequential: Stacked blocks in nn.Sequential.
+ """
+ layers = []
+ for _ in range(num_basic_block):
+ layers.append(basic_block(**kwarg))
+ return nn.Sequential(*layers)
+
+
+def act(act_type, inplace=True, neg_slope=0.2, n_prelu=1, beta=1.0):
+ """ activation helper """
+ act_type = act_type.lower()
+ if act_type == 'relu':
+ layer = nn.ReLU(inplace)
+ elif act_type in ('leakyrelu', 'lrelu'):
+ layer = nn.LeakyReLU(neg_slope, inplace)
+ elif act_type == 'prelu':
+ layer = nn.PReLU(num_parameters=n_prelu, init=neg_slope)
+ elif act_type == 'tanh': # [-1, 1] range output
+ layer = nn.Tanh()
+ elif act_type == 'sigmoid': # [0, 1] range output
+ layer = nn.Sigmoid()
+ else:
+ raise NotImplementedError('activation layer [{:s}] is not found'.format(act_type))
+ return layer
+
+
+class Identity(nn.Module):
+ def __init__(self, *kwargs):
+ super(Identity, self).__init__()
+
+ def forward(self, x, *kwargs):
+ return x
+
+
+def norm(norm_type, nc):
+ """ Return a normalization layer """
+ norm_type = norm_type.lower()
+ if norm_type == 'batch':
+ layer = nn.BatchNorm2d(nc, affine=True)
+ elif norm_type == 'instance':
+ layer = nn.InstanceNorm2d(nc, affine=False)
+ elif norm_type == 'none':
+ def norm_layer(x): return Identity()
+ else:
+ raise NotImplementedError('normalization layer [{:s}] is not found'.format(norm_type))
+ return layer
+
+
+def pad(pad_type, padding):
+ """ padding layer helper """
+ pad_type = pad_type.lower()
+ if padding == 0:
+ return None
+ if pad_type == 'reflect':
+ layer = nn.ReflectionPad2d(padding)
+ elif pad_type == 'replicate':
+ layer = nn.ReplicationPad2d(padding)
+ elif pad_type == 'zero':
+ layer = nn.ZeroPad2d(padding)
+ else:
+ raise NotImplementedError('padding layer [{:s}] is not implemented'.format(pad_type))
+ return layer
+
+
+def get_valid_padding(kernel_size, dilation):
+ kernel_size = kernel_size + (kernel_size - 1) * (dilation - 1)
+ padding = (kernel_size - 1) // 2
+ return padding
+
+
+class ShortcutBlock(nn.Module):
+ """ Elementwise sum the output of a submodule to its input """
+ def __init__(self, submodule):
+ super(ShortcutBlock, self).__init__()
+ self.sub = submodule
+
+ def forward(self, x):
+ output = x + self.sub(x)
+ return output
+
+ def __repr__(self):
+ return 'Identity + \n|' + self.sub.__repr__().replace('\n', '\n|')
+
+
+def sequential(*args):
+ """ Flatten Sequential. It unwraps nn.Sequential. """
+ if len(args) == 1:
+ if isinstance(args[0], OrderedDict):
+ raise NotImplementedError('sequential does not support OrderedDict input.')
+ return args[0] # No sequential is needed.
+ modules = []
+ for module in args:
+ if isinstance(module, nn.Sequential):
+ for submodule in module.children():
+ modules.append(submodule)
+ elif isinstance(module, nn.Module):
+ modules.append(module)
+ return nn.Sequential(*modules)
+
+
+def conv_block(in_nc, out_nc, kernel_size, stride=1, dilation=1, groups=1, bias=True,
+ pad_type='zero', norm_type=None, act_type='relu', mode='CNA', convtype='Conv2D',
+ spectral_norm=False):
+ """ Conv layer with padding, normalization, activation """
+ assert mode in ['CNA', 'NAC', 'CNAC'], 'Wrong conv mode [{:s}]'.format(mode)
+ padding = get_valid_padding(kernel_size, dilation)
+ p = pad(pad_type, padding) if pad_type and pad_type != 'zero' else None
+ padding = padding if pad_type == 'zero' else 0
+
+ if convtype=='PartialConv2D':
+ c = PartialConv2d(in_nc, out_nc, kernel_size=kernel_size, stride=stride, padding=padding,
+ dilation=dilation, bias=bias, groups=groups)
+ elif convtype=='DeformConv2D':
+ c = DeformConv2d(in_nc, out_nc, kernel_size=kernel_size, stride=stride, padding=padding,
+ dilation=dilation, bias=bias, groups=groups)
+ elif convtype=='Conv3D':
+ c = nn.Conv3d(in_nc, out_nc, kernel_size=kernel_size, stride=stride, padding=padding,
+ dilation=dilation, bias=bias, groups=groups)
+ else:
+ c = nn.Conv2d(in_nc, out_nc, kernel_size=kernel_size, stride=stride, padding=padding,
+ dilation=dilation, bias=bias, groups=groups)
+
+ if spectral_norm:
+ c = nn.utils.spectral_norm(c)
+
+ a = act(act_type) if act_type else None
+ if 'CNA' in mode:
+ n = norm(norm_type, out_nc) if norm_type else None
+ return sequential(p, c, n, a)
+ elif mode == 'NAC':
+ if norm_type is None and act_type is not None:
+ a = act(act_type, inplace=False)
+ n = norm(norm_type, in_nc) if norm_type else None
+ return sequential(n, a, p, c)
diff --git a/modules/extras.py b/modules/extras.py
index b853fa5b..22c5a1c1 100644
--- a/modules/extras.py
+++ b/modules/extras.py
@@ -39,9 +39,12 @@ def run_extras(extras_mode, resize_mode, image, image_folder, input_dir, output_
if input_dir == '':
return outputs, "Please select an input directory.", ''
- image_list = [file for file in [os.path.join(input_dir, x) for x in os.listdir(input_dir)] if os.path.isfile(file)]
+ image_list = [file for file in [os.path.join(input_dir, x) for x in sorted(os.listdir(input_dir))] if os.path.isfile(file)]
for img in image_list:
- image = Image.open(img)
+ try:
+ image = Image.open(img)
+ except Exception:
+ continue
imageArr.append(image)
imageNameArr.append(img)
else:
@@ -118,10 +121,14 @@ def run_extras(extras_mode, resize_mode, image, image_folder, input_dir, output_
while len(cached_images) > 2:
del cached_images[next(iter(cached_images.keys()))]
-
- images.save_image(image, path=outpath, basename="", seed=None, prompt=None, extension=opts.samples_format, info=info, short_filename=True,
- no_prompt=True, grid=False, pnginfo_section_name="extras", existing_info=existing_pnginfo,
- forced_filename=image_name if opts.use_original_name_batch else None)
+
+ if opts.use_original_name_batch and image_name != None:
+ basename = os.path.splitext(os.path.basename(image_name))[0]
+ else:
+ basename = ''
+
+ images.save_image(image, path=outpath, basename=basename, seed=None, prompt=None, extension=opts.samples_format, info=info, short_filename=True,
+ no_prompt=True, grid=False, pnginfo_section_name="extras", existing_info=existing_pnginfo, forced_filename=None)
if opts.enable_pnginfo:
image.info = existing_pnginfo
diff --git a/modules/generation_parameters_copypaste.py b/modules/generation_parameters_copypaste.py
index c27826b6..f73647da 100644
--- a/modules/generation_parameters_copypaste.py
+++ b/modules/generation_parameters_copypaste.py
@@ -4,13 +4,22 @@ import gradio as gr
from modules.shared import script_path
from modules import shared
-re_param_code = r"\s*([\w ]+):\s*([^,]+)(?:,|$)"
+re_param_code = r'\s*([\w ]+):\s*("(?:\\|\"|[^\"])+"|[^,]*)(?:,|$)'
re_param = re.compile(re_param_code)
re_params = re.compile(r"^(?:" + re_param_code + "){3,}$")
re_imagesize = re.compile(r"^(\d+)x(\d+)$")
type_of_gr_update = type(gr.update())
+def quote(text):
+ if ',' not in str(text):
+ return text
+
+ text = str(text)
+ text = text.replace('\\', '\\\\')
+ text = text.replace('"', '\\"')
+ return f'"{text}"'
+
def parse_generation_parameters(x: str):
"""parses generation parameters string, the one you see in text field under the picture in UI:
```
@@ -45,11 +54,8 @@ Steps: 20, Sampler: Euler a, CFG scale: 7, Seed: 965400086, Size: 512x512, Model
else:
prompt += ("" if prompt == "" else "\n") + line
- if len(prompt) > 0:
- res["Prompt"] = prompt
-
- if len(negative_prompt) > 0:
- res["Negative prompt"] = negative_prompt
+ res["Prompt"] = prompt
+ res["Negative prompt"] = negative_prompt
for k, v in re_param.findall(lastline):
m = re_imagesize.match(v)
@@ -86,7 +92,12 @@ def connect_paste(button, paste_fields, input_comp, js=None):
else:
try:
valtype = type(output.value)
- val = valtype(v)
+
+ if valtype == bool and v == "False":
+ val = False
+ else:
+ val = valtype(v)
+
res.append(gr.update(value=val))
except Exception:
res.append(gr.update())
diff --git a/modules/hypernetworks/hypernetwork.py b/modules/hypernetworks/hypernetwork.py
index b8695fc1..d647ea55 100644
--- a/modules/hypernetworks/hypernetwork.py
+++ b/modules/hypernetworks/hypernetwork.py
@@ -1,46 +1,100 @@
+import csv
import datetime
import glob
import html
import os
import sys
import traceback
-import tqdm
-import csv
+import modules.textual_inversion.dataset
import torch
-
-from ldm.util import default
-from modules import devices, shared, processing, sd_models
-import torch
-from torch import einsum
+import tqdm
from einops import rearrange, repeat
-import modules.textual_inversion.dataset
+from ldm.util import default
+from modules import devices, processing, sd_models, shared
from modules.textual_inversion import textual_inversion
from modules.textual_inversion.learn_schedule import LearnRateScheduler
+from torch import einsum
+from collections import defaultdict, deque
+from statistics import stdev, mean
class HypernetworkModule(torch.nn.Module):
multiplier = 1.0
-
- def __init__(self, dim, state_dict=None):
+ activation_dict = {
+ "relu": torch.nn.ReLU,
+ "leakyrelu": torch.nn.LeakyReLU,
+ "elu": torch.nn.ELU,
+ "swish": torch.nn.Hardswish,
+ }
+
+ def __init__(self, dim, state_dict=None, layer_structure=None, activation_func=None, add_layer_norm=False, use_dropout=False):
super().__init__()
- self.linear1 = torch.nn.Linear(dim, dim * 2)
- self.linear2 = torch.nn.Linear(dim * 2, dim)
+ assert layer_structure is not None, "layer_structure must not be None"
+ assert layer_structure[0] == 1, "Multiplier Sequence should start with size 1!"
+ assert layer_structure[-1] == 1, "Multiplier Sequence should end with size 1!"
+
+ linears = []
+ for i in range(len(layer_structure) - 1):
+
+ # Add a fully-connected layer
+ linears.append(torch.nn.Linear(int(dim * layer_structure[i]), int(dim * layer_structure[i+1])))
+
+ # Add an activation func
+ if activation_func == "linear" or activation_func is None:
+ pass
+ elif activation_func in self.activation_dict:
+ linears.append(self.activation_dict[activation_func]())
+ else:
+ raise RuntimeError(f'hypernetwork uses an unsupported activation function: {activation_func}')
+
+ # Add layer normalization
+ if add_layer_norm:
+ linears.append(torch.nn.LayerNorm(int(dim * layer_structure[i+1])))
+
+ # Add dropout expect last layer
+ if use_dropout and i < len(layer_structure) - 3:
+ linears.append(torch.nn.Dropout(p=0.3))
+
+ self.linear = torch.nn.Sequential(*linears)
if state_dict is not None:
- self.load_state_dict(state_dict, strict=True)
+ self.fix_old_state_dict(state_dict)
+ self.load_state_dict(state_dict)
else:
-
- self.linear1.weight.data.normal_(mean=0.0, std=0.01)
- self.linear1.bias.data.zero_()
- self.linear2.weight.data.normal_(mean=0.0, std=0.01)
- self.linear2.bias.data.zero_()
+ for layer in self.linear:
+ if type(layer) == torch.nn.Linear or type(layer) == torch.nn.LayerNorm:
+ layer.weight.data.normal_(mean=0.0, std=0.01)
+ layer.bias.data.zero_()
self.to(devices.device)
+ def fix_old_state_dict(self, state_dict):
+ changes = {
+ 'linear1.bias': 'linear.0.bias',
+ 'linear1.weight': 'linear.0.weight',
+ 'linear2.bias': 'linear.1.bias',
+ 'linear2.weight': 'linear.1.weight',
+ }
+
+ for fr, to in changes.items():
+ x = state_dict.get(fr, None)
+ if x is None:
+ continue
+
+ del state_dict[fr]
+ state_dict[to] = x
+
def forward(self, x):
- return x + (self.linear2(self.linear1(x))) * self.multiplier
+ return x + self.linear(x) * self.multiplier
+
+ def trainables(self):
+ layer_structure = []
+ for layer in self.linear:
+ if type(layer) == torch.nn.Linear or type(layer) == torch.nn.LayerNorm:
+ layer_structure += [layer.weight, layer.bias]
+ return layer_structure
def apply_strength(value=None):
@@ -51,16 +105,23 @@ class Hypernetwork:
filename = None
name = None
- def __init__(self, name=None, enable_sizes=None):
+ def __init__(self, name=None, enable_sizes=None, layer_structure=None, activation_func=None, add_layer_norm=False, use_dropout=False):
self.filename = None
self.name = name
self.layers = {}
self.step = 0
self.sd_checkpoint = None
self.sd_checkpoint_name = None
+ self.layer_structure = layer_structure
+ self.activation_func = activation_func
+ self.add_layer_norm = add_layer_norm
+ self.use_dropout = use_dropout
for size in enable_sizes or []:
- self.layers[size] = (HypernetworkModule(size), HypernetworkModule(size))
+ self.layers[size] = (
+ HypernetworkModule(size, None, self.layer_structure, self.activation_func, self.add_layer_norm, self.use_dropout),
+ HypernetworkModule(size, None, self.layer_structure, self.activation_func, self.add_layer_norm, self.use_dropout),
+ )
def weights(self):
res = []
@@ -68,7 +129,7 @@ class Hypernetwork:
for k, layers in self.layers.items():
for layer in layers:
layer.train()
- res += [layer.linear1.weight, layer.linear1.bias, layer.linear2.weight, layer.linear2.bias]
+ res += layer.trainables()
return res
@@ -80,6 +141,10 @@ class Hypernetwork:
state_dict['step'] = self.step
state_dict['name'] = self.name
+ state_dict['layer_structure'] = self.layer_structure
+ state_dict['activation_func'] = self.activation_func
+ state_dict['is_layer_norm'] = self.add_layer_norm
+ state_dict['use_dropout'] = self.use_dropout
state_dict['sd_checkpoint'] = self.sd_checkpoint
state_dict['sd_checkpoint_name'] = self.sd_checkpoint_name
@@ -92,9 +157,17 @@ class Hypernetwork:
state_dict = torch.load(filename, map_location='cpu')
+ self.layer_structure = state_dict.get('layer_structure', [1, 2, 1])
+ self.activation_func = state_dict.get('activation_func', None)
+ self.add_layer_norm = state_dict.get('is_layer_norm', False)
+ self.use_dropout = state_dict.get('use_dropout', False)
+
for size, sd in state_dict.items():
if type(size) == int:
- self.layers[size] = (HypernetworkModule(size, sd[0]), HypernetworkModule(size, sd[1]))
+ self.layers[size] = (
+ HypernetworkModule(size, sd[0], self.layer_structure, self.activation_func, self.add_layer_norm, self.use_dropout),
+ HypernetworkModule(size, sd[1], self.layer_structure, self.activation_func, self.add_layer_norm, self.use_dropout),
+ )
self.name = state_dict.get('name', self.name)
self.step = state_dict.get('step', 0)
@@ -196,7 +269,39 @@ def stack_conds(conds):
return torch.stack(conds)
+
+def statistics(data):
+ if len(data) < 2:
+ std = 0
+ else:
+ std = stdev(data)
+ total_information = f"loss:{mean(data):.3f}" + u"\u00B1" + f"({std/ (len(data) ** 0.5):.3f})"
+ recent_data = data[-32:]
+ if len(recent_data) < 2:
+ std = 0
+ else:
+ std = stdev(recent_data)
+ recent_information = f"recent 32 loss:{mean(recent_data):.3f}" + u"\u00B1" + f"({std / (len(recent_data) ** 0.5):.3f})"
+ return total_information, recent_information
+
+
+def report_statistics(loss_info:dict):
+ keys = sorted(loss_info.keys(), key=lambda x: sum(loss_info[x]) / len(loss_info[x]))
+ for key in keys:
+ try:
+ print("Loss statistics for file " + key)
+ info, recent = statistics(list(loss_info[key]))
+ print(info)
+ print(recent)
+ except Exception as e:
+ print(e)
+
+
+
def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, data_root, log_directory, training_width, training_height, steps, create_image_every, save_hypernetwork_every, template_file, preview_from_txt2img, preview_prompt, preview_negative_prompt, preview_steps, preview_sampler_index, preview_cfg_scale, preview_seed, preview_width, preview_height):
+ # images allows training previews to have infotext. Importing it at the top causes a circular import problem.
+ from modules import images
+
assert hypernetwork_name, 'hypernetwork not selected'
path = shared.hypernetworks.get(hypernetwork_name, None)
@@ -226,7 +331,6 @@ def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, data_root, log
shared.state.textinfo = f"Preparing dataset from {html.escape(data_root)}..."
with torch.autocast("cuda"):
ds = modules.textual_inversion.dataset.PersonalizedBase(data_root=data_root, width=training_width, height=training_height, repeats=shared.opts.training_image_repeats_per_epoch, placeholder_token=hypernetwork_name, model=shared.sd_model, device=devices.device, template_file=template_file, include_cond=True, batch_size=batch_size)
-
if unload:
shared.sd_model.cond_stage_model.to(devices.cpu)
shared.sd_model.first_stage_model.to(devices.cpu)
@@ -236,22 +340,34 @@ def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, data_root, log
for weight in weights:
weight.requires_grad = True
- losses = torch.zeros((32,))
+ size = len(ds.indexes)
+ loss_dict = defaultdict(lambda : deque(maxlen = 1024))
+ losses = torch.zeros((size,))
+ previous_mean_losses = [0]
+ previous_mean_loss = 0
+ print("Mean loss of {} elements".format(size))
last_saved_file = "<none>"
last_saved_image = "<none>"
+ forced_filename = "<none>"
ititial_step = hypernetwork.step or 0
if ititial_step > steps:
return hypernetwork, filename
scheduler = LearnRateScheduler(learn_rate, steps, ititial_step)
+ # if optimizer == "AdamW": or else Adam / AdamW / SGD, etc...
optimizer = torch.optim.AdamW(weights, lr=scheduler.learn_rate)
+ steps_without_grad = 0
+
pbar = tqdm.tqdm(enumerate(ds), total=steps - ititial_step)
for i, entries in pbar:
hypernetwork.step = i + ititial_step
-
+ if len(loss_dict) > 0:
+ previous_mean_losses = [i[-1] for i in loss_dict.values()]
+ previous_mean_loss = mean(previous_mean_losses)
+
scheduler.apply(optimizer, hypernetwork.step)
if scheduler.finished:
break
@@ -261,33 +377,52 @@ def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, data_root, log
with torch.autocast("cuda"):
c = stack_conds([entry.cond for entry in entries]).to(devices.device)
-# c = torch.vstack([entry.cond for entry in entries]).to(devices.device)
+ # c = torch.vstack([entry.cond for entry in entries]).to(devices.device)
x = torch.stack([entry.latent for entry in entries]).to(devices.device)
loss = shared.sd_model(x, c)[0]
del x
del c
losses[hypernetwork.step % losses.shape[0]] = loss.item()
-
+ for entry in entries:
+ loss_dict[entry.filename].append(loss.item())
+
optimizer.zero_grad()
+ weights[0].grad = None
loss.backward()
+
+ if weights[0].grad is None:
+ steps_without_grad += 1
+ else:
+ steps_without_grad = 0
+ assert steps_without_grad < 10, 'no gradient found for the trained weight after backward() for 10 steps in a row; this is a bug; training cannot continue'
+
optimizer.step()
- mean_loss = losses.mean()
- if torch.isnan(mean_loss):
+
+ if torch.isnan(losses[hypernetwork.step % losses.shape[0]]):
raise RuntimeError("Loss diverged.")
- pbar.set_description(f"loss: {mean_loss:.7f}")
+
+ if len(previous_mean_losses) > 1:
+ std = stdev(previous_mean_losses)
+ else:
+ std = 0
+ dataset_loss_info = f"dataset loss:{mean(previous_mean_losses):.3f}" + u"\u00B1" + f"({std / (len(previous_mean_losses) ** 0.5):.3f})"
+ pbar.set_description(dataset_loss_info)
if hypernetwork.step > 0 and hypernetwork_dir is not None and hypernetwork.step % save_hypernetwork_every == 0:
- last_saved_file = os.path.join(hypernetwork_dir, f'{hypernetwork_name}-{hypernetwork.step}.pt')
+ # Before saving, change name to match current checkpoint.
+ hypernetwork.name = f'{hypernetwork_name}-{hypernetwork.step}'
+ last_saved_file = os.path.join(hypernetwork_dir, f'{hypernetwork.name}.pt')
hypernetwork.save(last_saved_file)
textual_inversion.write_loss(log_directory, "hypernetwork_loss.csv", hypernetwork.step, len(ds), {
- "loss": f"{mean_loss:.7f}",
+ "loss": f"{previous_mean_loss:.7f}",
"learn_rate": scheduler.learn_rate
})
if hypernetwork.step > 0 and images_dir is not None and hypernetwork.step % create_image_every == 0:
- last_saved_image = os.path.join(images_dir, f'{hypernetwork_name}-{hypernetwork.step}.png')
+ forced_filename = f'{hypernetwork_name}-{hypernetwork.step}'
+ last_saved_image = os.path.join(images_dir, forced_filename)
optimizer.zero_grad()
shared.sd_model.cond_stage_model.to(devices.device)
@@ -323,27 +458,29 @@ def train_hypernetwork(hypernetwork_name, learn_rate, batch_size, data_root, log
if image is not None:
shared.state.current_image = image
- image.save(last_saved_image)
+ last_saved_image, last_text_info = images.save_image(image, images_dir, "", p.seed, p.prompt, shared.opts.samples_format, processed.infotexts[0], p=p, forced_filename=forced_filename)
last_saved_image += f", prompt: {preview_text}"
shared.state.job_no = hypernetwork.step
shared.state.textinfo = f"""
<p>
-Loss: {mean_loss:.7f}<br/>
+Loss: {previous_mean_loss:.7f}<br/>
Step: {hypernetwork.step}<br/>
Last prompt: {html.escape(entries[0].cond_text)}<br/>
-Last saved embedding: {html.escape(last_saved_file)}<br/>
+Last saved hypernetwork: {html.escape(last_saved_file)}<br/>
Last saved image: {html.escape(last_saved_image)}<br/>
</p>
"""
-
+
+ report_statistics(loss_dict)
checkpoint = sd_models.select_checkpoint()
hypernetwork.sd_checkpoint = checkpoint.hash
hypernetwork.sd_checkpoint_name = checkpoint.model_name
+ # Before saving for the last time, change name back to the base name (as opposed to the save_hypernetwork_every step-suffixed naming convention).
+ hypernetwork.name = hypernetwork_name
+ filename = os.path.join(shared.cmd_opts.hypernetwork_dir, f'{hypernetwork.name}.pt')
hypernetwork.save(filename)
return hypernetwork, filename
-
-
diff --git a/modules/hypernetworks/ui.py b/modules/hypernetworks/ui.py
index dfa599af..2b472d87 100644
--- a/modules/hypernetworks/ui.py
+++ b/modules/hypernetworks/ui.py
@@ -1,19 +1,33 @@
import html
import os
+import re
import gradio as gr
-
-import modules.textual_inversion.textual_inversion
import modules.textual_inversion.preprocess
-from modules import sd_hijack, shared, devices
+import modules.textual_inversion.textual_inversion
+from modules import devices, sd_hijack, shared
from modules.hypernetworks import hypernetwork
-def create_hypernetwork(name, enable_sizes):
- fn = os.path.join(shared.cmd_opts.hypernetwork_dir, f"{name}.pt")
- assert not os.path.exists(fn), f"file {fn} already exists"
+def create_hypernetwork(name, enable_sizes, overwrite_old, layer_structure=None, activation_func=None, add_layer_norm=False, use_dropout=False):
+ # Remove illegal characters from name.
+ name = "".join( x for x in name if (x.isalnum() or x in "._- "))
- hypernet = modules.hypernetworks.hypernetwork.Hypernetwork(name=name, enable_sizes=[int(x) for x in enable_sizes])
+ fn = os.path.join(shared.cmd_opts.hypernetwork_dir, f"{name}.pt")
+ if not overwrite_old:
+ assert not os.path.exists(fn), f"file {fn} already exists"
+
+ if type(layer_structure) == str:
+ layer_structure = [float(x.strip()) for x in layer_structure.split(",")]
+
+ hypernet = modules.hypernetworks.hypernetwork.Hypernetwork(
+ name=name,
+ enable_sizes=[int(x) for x in enable_sizes],
+ layer_structure=layer_structure,
+ activation_func=activation_func,
+ add_layer_norm=add_layer_norm,
+ use_dropout=use_dropout,
+ )
hypernet.save(fn)
shared.reload_hypernetworks()
diff --git a/modules/images.py b/modules/images.py
index b9589563..286de2ae 100644
--- a/modules/images.py
+++ b/modules/images.py
@@ -1,4 +1,8 @@
import datetime
+import sys
+import traceback
+
+import pytz
import io
import math
import os
@@ -12,7 +16,7 @@ from PIL import Image, ImageFont, ImageDraw, PngImagePlugin
from fonts.ttf import Roboto
import string
-from modules import sd_samplers, shared
+from modules import sd_samplers, shared, script_callbacks
from modules.shared import opts, cmd_opts
LANCZOS = (Image.Resampling.LANCZOS if hasattr(Image, 'Resampling') else Image.LANCZOS)
@@ -273,10 +277,15 @@ invalid_filename_chars = '<>:"/\\|?*\n'
invalid_filename_prefix = ' '
invalid_filename_postfix = ' .'
re_nonletters = re.compile(r'[\s' + string.punctuation + ']+')
+re_pattern = re.compile(r"([^\[\]]+|\[([^]]+)]|[\[\]]*)")
+re_pattern_arg = re.compile(r"(.*)<([^>]*)>$")
max_filename_part_length = 128
def sanitize_filename_part(text, replace_spaces=True):
+ if text is None:
+ return None
+
if replace_spaces:
text = text.replace(' ', '_')
@@ -286,49 +295,106 @@ def sanitize_filename_part(text, replace_spaces=True):
return text
-def apply_filename_pattern(x, p, seed, prompt):
- max_prompt_words = opts.directories_max_prompt_words
-
- if seed is not None:
- x = x.replace("[seed]", str(seed))
-
- if p is not None:
- x = x.replace("[steps]", str(p.steps))
- x = x.replace("[cfg]", str(p.cfg_scale))
- x = x.replace("[width]", str(p.width))
- x = x.replace("[height]", str(p.height))
- x = x.replace("[styles]", sanitize_filename_part(", ".join([x for x in p.styles if not x == "None"]) or "None", replace_spaces=False))
- x = x.replace("[sampler]", sanitize_filename_part(sd_samplers.samplers[p.sampler_index].name, replace_spaces=False))
-
- x = x.replace("[model_hash]", getattr(p, "sd_model_hash", shared.sd_model.sd_model_hash))
- x = x.replace("[date]", datetime.date.today().isoformat())
- x = x.replace("[datetime]", datetime.datetime.now().strftime("%Y%m%d%H%M%S"))
- x = x.replace("[job_timestamp]", getattr(p, "job_timestamp", shared.state.job_timestamp))
+class FilenameGenerator:
+ replacements = {
+ 'seed': lambda self: self.seed if self.seed is not None else '',
+ 'steps': lambda self: self.p and self.p.steps,
+ 'cfg': lambda self: self.p and self.p.cfg_scale,
+ 'width': lambda self: self.p and self.p.width,
+ 'height': lambda self: self.p and self.p.height,
+ 'styles': lambda self: self.p and sanitize_filename_part(", ".join([style for style in self.p.styles if not style == "None"]) or "None", replace_spaces=False),
+ 'sampler': lambda self: self.p and sanitize_filename_part(sd_samplers.samplers[self.p.sampler_index].name, replace_spaces=False),
+ 'model_hash': lambda self: getattr(self.p, "sd_model_hash", shared.sd_model.sd_model_hash),
+ 'date': lambda self: datetime.datetime.now().strftime('%Y-%m-%d'),
+ 'datetime': lambda self, *args: self.datetime(*args), # accepts formats: [datetime], [datetime<Format>], [datetime<Format><Time Zone>]
+ 'job_timestamp': lambda self: getattr(self.p, "job_timestamp", shared.state.job_timestamp),
+ 'prompt': lambda self: sanitize_filename_part(self.prompt),
+ 'prompt_no_styles': lambda self: self.prompt_no_style(),
+ 'prompt_spaces': lambda self: sanitize_filename_part(self.prompt, replace_spaces=False),
+ 'prompt_words': lambda self: self.prompt_words(),
+ }
+ default_time_format = '%Y%m%d%H%M%S'
+
+ def __init__(self, p, seed, prompt):
+ self.p = p
+ self.seed = seed
+ self.prompt = prompt
+
+ def prompt_no_style(self):
+ if self.p is None or self.prompt is None:
+ return None
+
+ prompt_no_style = self.prompt
+ for style in shared.prompt_styles.get_style_prompts(self.p.styles):
+ if len(style) > 0:
+ for part in style.split("{prompt}"):
+ prompt_no_style = prompt_no_style.replace(part, "").replace(", ,", ",").strip().strip(',')
+
+ prompt_no_style = prompt_no_style.replace(style, "").strip().strip(',').strip()
+
+ return sanitize_filename_part(prompt_no_style, replace_spaces=False)
+
+ def prompt_words(self):
+ words = [x for x in re_nonletters.split(self.prompt or "") if len(x) > 0]
+ if len(words) == 0:
+ words = ["empty"]
+ return sanitize_filename_part(" ".join(words[0:opts.directories_max_prompt_words]), replace_spaces=False)
+
+ def datetime(self, *args):
+ time_datetime = datetime.datetime.now()
+
+ time_format = args[0] if len(args) > 0 else self.default_time_format
+ try:
+ time_zone = pytz.timezone(args[1]) if len(args) > 1 else None
+ except pytz.exceptions.UnknownTimeZoneError as _:
+ time_zone = None
+
+ time_zone_time = time_datetime.astimezone(time_zone)
+ try:
+ formatted_time = time_zone_time.strftime(time_format)
+ except (ValueError, TypeError) as _:
+ formatted_time = time_zone_time.strftime(self.default_time_format)
+
+ return sanitize_filename_part(formatted_time, replace_spaces=False)
+
+ def apply(self, x):
+ res = ''
+
+ for m in re_pattern.finditer(x):
+ text, pattern = m.groups()
+
+ if pattern is None:
+ res += text
+ continue
- # Apply [prompt] at last. Because it may contain any replacement word.^M
- if prompt is not None:
- x = x.replace("[prompt]", sanitize_filename_part(prompt))
- if "[prompt_no_styles]" in x:
- prompt_no_style = prompt
- for style in shared.prompt_styles.get_style_prompts(p.styles):
- if len(style) > 0:
- style_parts = [y for y in style.split("{prompt}")]
- for part in style_parts:
- prompt_no_style = prompt_no_style.replace(part, "").replace(", ,", ",").strip().strip(',')
- prompt_no_style = prompt_no_style.replace(style, "").strip().strip(',').strip()
- x = x.replace("[prompt_no_styles]", sanitize_filename_part(prompt_no_style, replace_spaces=False))
+ pattern_args = []
+ while True:
+ m = re_pattern_arg.match(pattern)
+ if m is None:
+ break
+
+ pattern, arg = m.groups()
+ pattern_args.insert(0, arg)
+
+ fun = self.replacements.get(pattern.lower())
+ if fun is not None:
+ try:
+ replacement = fun(self, *pattern_args)
+ except Exception:
+ replacement = None
+ print(f"Error adding [{pattern}] to filename", file=sys.stderr)
+ print(traceback.format_exc(), file=sys.stderr)
+
+ if replacement is None:
+ res += f'[{pattern}]'
+ else:
+ res += str(replacement)
- x = x.replace("[prompt_spaces]", sanitize_filename_part(prompt, replace_spaces=False))
- if "[prompt_words]" in x:
- words = [x for x in re_nonletters.split(prompt or "") if len(x) > 0]
- if len(words) == 0:
- words = ["empty"]
- x = x.replace("[prompt_words]", sanitize_filename_part(" ".join(words[0:max_prompt_words]), replace_spaces=False))
+ continue
- if cmd_opts.hide_ui_dir_config:
- x = re.sub(r'^[\\/]+|\.{2,}[\\/]+|[\\/]+\.{2,}', '', x)
+ res += f'[{pattern}]'
- return x
+ return res
def get_next_sequence_number(path, basename):
@@ -354,7 +420,7 @@ def get_next_sequence_number(path, basename):
def save_image(image, path, basename, seed=None, prompt=None, extension='png', info=None, short_filename=False, no_prompt=False, grid=False, pnginfo_section_name='parameters', p=None, existing_info=None, forced_filename=None, suffix="", save_to_dirs=None):
- '''Save an image.
+ """Save an image.
Args:
image (`PIL.Image`):
@@ -385,18 +451,8 @@ def save_image(image, path, basename, seed=None, prompt=None, extension='png', i
The full path of the saved imaged.
txt_fullfn (`str` or None):
If a text file is saved for this image, this will be its full path. Otherwise None.
- '''
- if short_filename or prompt is None or seed is None:
- file_decoration = ""
- elif opts.save_to_dirs:
- file_decoration = opts.samples_filename_pattern or "[seed]"
- else:
- file_decoration = opts.samples_filename_pattern or "[seed]-[prompt_spaces]"
-
- if file_decoration != "":
- file_decoration = "-" + file_decoration.lower()
-
- file_decoration = apply_filename_pattern(file_decoration, p, seed, prompt) + suffix
+ """
+ namegen = FilenameGenerator(p, seed, prompt)
if extension == 'png' and opts.enable_pnginfo and info is not None:
pnginfo = PngImagePlugin.PngInfo()
@@ -413,21 +469,39 @@ def save_image(image, path, basename, seed=None, prompt=None, extension='png', i
save_to_dirs = (grid and opts.grid_save_to_dirs) or (not grid and opts.save_to_dirs and not no_prompt)
if save_to_dirs:
- dirname = apply_filename_pattern(opts.directories_filename_pattern or "[prompt_words]", p, seed, prompt).strip('\\ /')
+ dirname = namegen.apply(opts.directories_filename_pattern or "[prompt_words]").lstrip(' ').rstrip('\\ /')
path = os.path.join(path, dirname)
os.makedirs(path, exist_ok=True)
if forced_filename is None:
- basecount = get_next_sequence_number(path, basename)
- fullfn = "a.png"
- fullfn_without_extension = "a"
- for i in range(500):
- fn = f"{basecount + i:05}" if basename == '' else f"{basename}-{basecount + i:04}"
- fullfn = os.path.join(path, f"{fn}{file_decoration}.{extension}")
- fullfn_without_extension = os.path.join(path, f"{fn}{file_decoration}")
- if not os.path.exists(fullfn):
- break
+ if short_filename or seed is None:
+ file_decoration = ""
+ elif opts.save_to_dirs:
+ file_decoration = opts.samples_filename_pattern or "[seed]"
+ else:
+ file_decoration = opts.samples_filename_pattern or "[seed]-[prompt_spaces]"
+
+ add_number = opts.save_images_add_number or file_decoration == ''
+
+ if file_decoration != "" and add_number:
+ file_decoration = "-" + file_decoration
+
+ file_decoration = namegen.apply(file_decoration) + suffix
+
+ if add_number:
+ basecount = get_next_sequence_number(path, basename)
+ fullfn = None
+ fullfn_without_extension = None
+ for i in range(500):
+ fn = f"{basecount + i:05}" if basename == '' else f"{basename}-{basecount + i:04}"
+ fullfn = os.path.join(path, f"{fn}{file_decoration}.{extension}")
+ fullfn_without_extension = os.path.join(path, f"{fn}{file_decoration}")
+ if not os.path.exists(fullfn):
+ break
+ else:
+ fullfn = os.path.join(path, f"{file_decoration}.{extension}")
+ fullfn_without_extension = os.path.join(path, file_decoration)
else:
fullfn = os.path.join(path, f"{forced_filename}.{extension}")
fullfn_without_extension = os.path.join(path, forced_filename)
@@ -467,6 +541,7 @@ def save_image(image, path, basename, seed=None, prompt=None, extension='png', i
else:
txt_fullfn = None
+ script_callbacks.image_saved_callback(image, p, fullfn, txt_fullfn)
return fullfn, txt_fullfn
diff --git a/modules/images_history.py b/modules/images_history.py
deleted file mode 100644
index 46b23e56..00000000
--- a/modules/images_history.py
+++ /dev/null
@@ -1,183 +0,0 @@
-import os
-import shutil
-import sys
-
-def traverse_all_files(output_dir, image_list, curr_dir=None):
- curr_path = output_dir if curr_dir is None else os.path.join(output_dir, curr_dir)
- try:
- f_list = os.listdir(curr_path)
- except:
- if curr_dir[-10:].rfind(".") > 0 and curr_dir[-4:] != ".txt":
- image_list.append(curr_dir)
- return image_list
- for file in f_list:
- file = file if curr_dir is None else os.path.join(curr_dir, file)
- file_path = os.path.join(curr_path, file)
- if file[-4:] == ".txt":
- pass
- elif os.path.isfile(file_path) and file[-10:].rfind(".") > 0:
- image_list.append(file)
- else:
- image_list = traverse_all_files(output_dir, image_list, file)
- return image_list
-
-
-def get_recent_images(dir_name, page_index, step, image_index, tabname):
- page_index = int(page_index)
- image_list = []
- if not os.path.exists(dir_name):
- pass
- elif os.path.isdir(dir_name):
- image_list = traverse_all_files(dir_name, image_list)
- image_list = sorted(image_list, key=lambda file: -os.path.getctime(os.path.join(dir_name, file)))
- else:
- print(f'ERROR: "{dir_name}" is not a directory. Check the path in the settings.', file=sys.stderr)
- num = 48 if tabname != "extras" else 12
- max_page_index = len(image_list) // num + 1
- page_index = max_page_index if page_index == -1 else page_index + step
- page_index = 1 if page_index < 1 else page_index
- page_index = max_page_index if page_index > max_page_index else page_index
- idx_frm = (page_index - 1) * num
- image_list = image_list[idx_frm:idx_frm + num]
- image_index = int(image_index)
- if image_index < 0 or image_index > len(image_list) - 1:
- current_file = None
- hidden = None
- else:
- current_file = image_list[int(image_index)]
- hidden = os.path.join(dir_name, current_file)
- return [os.path.join(dir_name, file) for file in image_list], page_index, image_list, current_file, hidden, ""
-
-
-def first_page_click(dir_name, page_index, image_index, tabname):
- return get_recent_images(dir_name, 1, 0, image_index, tabname)
-
-
-def end_page_click(dir_name, page_index, image_index, tabname):
- return get_recent_images(dir_name, -1, 0, image_index, tabname)
-
-
-def prev_page_click(dir_name, page_index, image_index, tabname):
- return get_recent_images(dir_name, page_index, -1, image_index, tabname)
-
-
-def next_page_click(dir_name, page_index, image_index, tabname):
- return get_recent_images(dir_name, page_index, 1, image_index, tabname)
-
-
-def page_index_change(dir_name, page_index, image_index, tabname):
- return get_recent_images(dir_name, page_index, 0, image_index, tabname)
-
-
-def show_image_info(num, image_path, filenames):
- # print(f"select image {num}")
- file = filenames[int(num)]
- return file, num, os.path.join(image_path, file)
-
-
-def delete_image(delete_num, tabname, dir_name, name, page_index, filenames, image_index):
- if name == "":
- return filenames, delete_num
- else:
- delete_num = int(delete_num)
- index = list(filenames).index(name)
- i = 0
- new_file_list = []
- for name in filenames:
- if i >= index and i < index + delete_num:
- path = os.path.join(dir_name, name)
- if os.path.exists(path):
- print(f"Delete file {path}")
- os.remove(path)
- txt_file = os.path.splitext(path)[0] + ".txt"
- if os.path.exists(txt_file):
- os.remove(txt_file)
- else:
- print(f"Not exists file {path}")
- else:
- new_file_list.append(name)
- i += 1
- return new_file_list, 1
-
-
-def show_images_history(gr, opts, tabname, run_pnginfo, switch_dict):
- if opts.outdir_samples != "":
- dir_name = opts.outdir_samples
- elif tabname == "txt2img":
- dir_name = opts.outdir_txt2img_samples
- elif tabname == "img2img":
- dir_name = opts.outdir_img2img_samples
- elif tabname == "extras":
- dir_name = opts.outdir_extras_samples
- else:
- return
- with gr.Row():
- renew_page = gr.Button('Renew Page', elem_id=tabname + "_images_history_renew_page")
- first_page = gr.Button('First Page')
- prev_page = gr.Button('Prev Page')
- page_index = gr.Number(value=1, label="Page Index")
- next_page = gr.Button('Next Page')
- end_page = gr.Button('End Page')
- with gr.Row(elem_id=tabname + "_images_history"):
- with gr.Row():
- with gr.Column(scale=2):
- history_gallery = gr.Gallery(show_label=False, elem_id=tabname + "_images_history_gallery").style(grid=6)
- with gr.Row():
- delete_num = gr.Number(value=1, interactive=True, label="number of images to delete consecutively next")
- delete = gr.Button('Delete', elem_id=tabname + "_images_history_del_button")
- with gr.Column():
- with gr.Row():
- pnginfo_send_to_txt2img = gr.Button('Send to txt2img')
- pnginfo_send_to_img2img = gr.Button('Send to img2img')
- with gr.Row():
- with gr.Column():
- img_file_info = gr.Textbox(label="Generate Info", interactive=False)
- img_file_name = gr.Textbox(label="File Name", interactive=False)
- with gr.Row():
- # hiden items
-
- img_path = gr.Textbox(dir_name.rstrip("/"), visible=False)
- tabname_box = gr.Textbox(tabname, visible=False)
- image_index = gr.Textbox(value=-1, visible=False)
- set_index = gr.Button('set_index', elem_id=tabname + "_images_history_set_index", visible=False)
- filenames = gr.State()
- hidden = gr.Image(type="pil", visible=False)
- info1 = gr.Textbox(visible=False)
- info2 = gr.Textbox(visible=False)
-
- # turn pages
- gallery_inputs = [img_path, page_index, image_index, tabname_box]
- gallery_outputs = [history_gallery, page_index, filenames, img_file_name, hidden, img_file_name]
-
- first_page.click(first_page_click, _js="images_history_turnpage", inputs=gallery_inputs, outputs=gallery_outputs)
- next_page.click(next_page_click, _js="images_history_turnpage", inputs=gallery_inputs, outputs=gallery_outputs)
- prev_page.click(prev_page_click, _js="images_history_turnpage", inputs=gallery_inputs, outputs=gallery_outputs)
- end_page.click(end_page_click, _js="images_history_turnpage", inputs=gallery_inputs, outputs=gallery_outputs)
- page_index.submit(page_index_change, _js="images_history_turnpage", inputs=gallery_inputs, outputs=gallery_outputs)
- renew_page.click(page_index_change, _js="images_history_turnpage", inputs=gallery_inputs, outputs=gallery_outputs)
- # page_index.change(page_index_change, inputs=[tabname_box, img_path, page_index], outputs=[history_gallery, page_index])
-
- # other funcitons
- set_index.click(show_image_info, _js="images_history_get_current_img", inputs=[tabname_box, img_path, filenames], outputs=[img_file_name, image_index, hidden])
- img_file_name.change(fn=None, _js="images_history_enable_del_buttons", inputs=None, outputs=None)
- delete.click(delete_image, _js="images_history_delete", inputs=[delete_num, tabname_box, img_path, img_file_name, page_index, filenames, image_index], outputs=[filenames, delete_num])
- hidden.change(fn=run_pnginfo, inputs=[hidden], outputs=[info1, img_file_info, info2])
-
- # pnginfo.click(fn=run_pnginfo, inputs=[hidden], outputs=[info1, img_file_info, info2])
- switch_dict["fn"](pnginfo_send_to_txt2img, switch_dict["t2i"], img_file_info, 'switch_to_txt2img')
- switch_dict["fn"](pnginfo_send_to_img2img, switch_dict["i2i"], img_file_info, 'switch_to_img2img_img2img')
-
-
-def create_history_tabs(gr, opts, run_pnginfo, switch_dict):
- with gr.Blocks(analytics_enabled=False) as images_history:
- with gr.Tabs() as tabs:
- with gr.Tab("txt2img history"):
- with gr.Blocks(analytics_enabled=False) as images_history_txt2img:
- show_images_history(gr, opts, "txt2img", run_pnginfo, switch_dict)
- with gr.Tab("img2img history"):
- with gr.Blocks(analytics_enabled=False) as images_history_img2img:
- show_images_history(gr, opts, "img2img", run_pnginfo, switch_dict)
- with gr.Tab("extras history"):
- with gr.Blocks(analytics_enabled=False) as images_history_img2img:
- show_images_history(gr, opts, "extras", run_pnginfo, switch_dict)
- return images_history
diff --git a/modules/img2img.py b/modules/img2img.py
index 24126774..8d9f7cf9 100644
--- a/modules/img2img.py
+++ b/modules/img2img.py
@@ -109,6 +109,9 @@ def img2img(mode: int, prompt: str, negative_prompt: str, prompt_style: str, pro
inpainting_mask_invert=inpainting_mask_invert,
)
+ p.scripts = modules.scripts.scripts_txt2img
+ p.script_args = args
+
if shared.cmd_opts.enable_console_prompts:
print(f"\nimg2img: {prompt}", file=shared.progress_print_out)
diff --git a/modules/interrogate.py b/modules/interrogate.py
index 64b91eb4..65b05d34 100644
--- a/modules/interrogate.py
+++ b/modules/interrogate.py
@@ -28,9 +28,11 @@ class InterrogateModels:
clip_preprocess = None
categories = None
dtype = None
+ running_on_cpu = None
def __init__(self, content_dir):
self.categories = []
+ self.running_on_cpu = devices.device_interrogate == torch.device("cpu")
if os.path.exists(content_dir):
for filename in os.listdir(content_dir):
@@ -53,7 +55,11 @@ class InterrogateModels:
def load_clip_model(self):
import clip
- model, preprocess = clip.load(clip_model_name)
+ if self.running_on_cpu:
+ model, preprocess = clip.load(clip_model_name, device="cpu")
+ else:
+ model, preprocess = clip.load(clip_model_name)
+
model.eval()
model = model.to(devices.device_interrogate)
@@ -62,14 +68,14 @@ class InterrogateModels:
def load(self):
if self.blip_model is None:
self.blip_model = self.load_blip_model()
- if not shared.cmd_opts.no_half:
+ if not shared.cmd_opts.no_half and not self.running_on_cpu:
self.blip_model = self.blip_model.half()
self.blip_model = self.blip_model.to(devices.device_interrogate)
if self.clip_model is None:
self.clip_model, self.clip_preprocess = self.load_clip_model()
- if not shared.cmd_opts.no_half:
+ if not shared.cmd_opts.no_half and not self.running_on_cpu:
self.clip_model = self.clip_model.half()
self.clip_model = self.clip_model.to(devices.device_interrogate)
diff --git a/modules/lowvram.py b/modules/lowvram.py
index 7eba1349..f327c3df 100644
--- a/modules/lowvram.py
+++ b/modules/lowvram.py
@@ -1,9 +1,8 @@
import torch
-from modules.devices import get_optimal_device
+from modules import devices
module_in_gpu = None
cpu = torch.device("cpu")
-device = gpu = get_optimal_device()
def send_everything_to_cpu():
@@ -33,7 +32,7 @@ def setup_for_low_vram(sd_model, use_medvram):
if module_in_gpu is not None:
module_in_gpu.to(cpu)
- module.to(gpu)
+ module.to(devices.device)
module_in_gpu = module
# see below for register_forward_pre_hook;
@@ -51,7 +50,7 @@ def setup_for_low_vram(sd_model, use_medvram):
# send the model to GPU. Then put modules back. the modules will be in CPU.
stored = sd_model.cond_stage_model.transformer, sd_model.first_stage_model, sd_model.model
sd_model.cond_stage_model.transformer, sd_model.first_stage_model, sd_model.model = None, None, None
- sd_model.to(device)
+ sd_model.to(devices.device)
sd_model.cond_stage_model.transformer, sd_model.first_stage_model, sd_model.model = stored
# register hooks for those the first two models
@@ -70,7 +69,7 @@ def setup_for_low_vram(sd_model, use_medvram):
# so that only one of them is in GPU at a time
stored = diff_model.input_blocks, diff_model.middle_block, diff_model.output_blocks, diff_model.time_embed
diff_model.input_blocks, diff_model.middle_block, diff_model.output_blocks, diff_model.time_embed = None, None, None, None
- sd_model.model.to(device)
+ sd_model.model.to(devices.device)
diff_model.input_blocks, diff_model.middle_block, diff_model.output_blocks, diff_model.time_embed = stored
# install hooks for bits of third model
diff --git a/modules/processing.py b/modules/processing.py
index ea926fc3..c61bbfbd 100644
--- a/modules/processing.py
+++ b/modules/processing.py
@@ -12,7 +12,7 @@ from skimage import exposure
from typing import Any, Dict, List, Optional
import modules.sd_hijack
-from modules import devices, prompt_parser, masking, sd_samplers, lowvram
+from modules import devices, prompt_parser, masking, sd_samplers, lowvram, generation_parameters_copypaste
from modules.sd_hijack import model_hijack
from modules.shared import opts, cmd_opts, state
import modules.shared as shared
@@ -47,6 +47,25 @@ def apply_color_correction(correction, image):
return image
+def apply_overlay(image, paste_loc, index, overlays):
+ if overlays is None or index >= len(overlays):
+ return image
+
+ overlay = overlays[index]
+
+ if paste_loc is not None:
+ x, y, w, h = paste_loc
+ base_image = Image.new('RGBA', (overlay.width, overlay.height))
+ image = images.resize_image(1, image, w, h)
+ base_image.paste(image, (x, y))
+ image = base_image
+
+ image = image.convert('RGBA')
+ image.alpha_composite(overlay)
+ image = image.convert('RGB')
+
+ return image
+
def get_correct_sampler(p):
if isinstance(p, modules.processing.StableDiffusionProcessingTxt2Img):
return sd_samplers.samplers
@@ -104,6 +123,12 @@ class StableDiffusionProcessing():
self.seed_resize_from_h = 0
self.seed_resize_from_w = 0
+ self.scripts = None
+ self.script_args = None
+ self.all_prompts = None
+ self.all_seeds = None
+ self.all_subseeds = None
+
def init(self, all_prompts, all_seeds, all_subseeds):
pass
@@ -304,7 +329,7 @@ def create_infotext(p, all_prompts, all_seeds, all_subseeds, comments, iteration
"Size": f"{p.width}x{p.height}",
"Model hash": getattr(p, 'sd_model_hash', None if not opts.add_model_hash_to_info or not shared.sd_model.sd_model_hash else shared.sd_model.sd_model_hash),
"Model": (None if not opts.add_model_name_to_info or not shared.sd_model.sd_checkpoint_info.model_name else shared.sd_model.sd_checkpoint_info.model_name.replace(',', '').replace(':', '')),
- "Hypernet": (None if shared.loaded_hypernetwork is None else shared.loaded_hypernetwork.name.replace(',', '').replace(':', '')),
+ "Hypernet": (None if shared.loaded_hypernetwork is None else shared.loaded_hypernetwork.name),
"Batch size": (None if p.batch_size < 2 else p.batch_size),
"Batch pos": (None if p.batch_size < 2 else position_in_batch),
"Variation seed": (None if p.subseed_strength == 0 else all_subseeds[index]),
@@ -318,7 +343,7 @@ def create_infotext(p, all_prompts, all_seeds, all_subseeds, comments, iteration
generation_params.update(p.extra_generation_params)
- generation_params_text = ", ".join([k if k == v else f'{k}: {v}' for k, v in generation_params.items() if v is not None])
+ generation_params_text = ", ".join([k if k == v else f'{k}: {generation_parameters_copypaste.quote(v)}' for k, v in generation_params.items() if v is not None])
negative_prompt_text = "\nNegative prompt: " + p.negative_prompt if p.negative_prompt else ""
@@ -350,32 +375,35 @@ def process_images(p: StableDiffusionProcessing) -> Processed:
shared.prompt_styles.apply_styles(p)
if type(p.prompt) == list:
- all_prompts = p.prompt
+ p.all_prompts = p.prompt
else:
- all_prompts = p.batch_size * p.n_iter * [p.prompt]
+ p.all_prompts = p.batch_size * p.n_iter * [p.prompt]
if type(seed) == list:
- all_seeds = seed
+ p.all_seeds = seed
else:
- all_seeds = [int(seed) + (x if p.subseed_strength == 0 else 0) for x in range(len(all_prompts))]
+ p.all_seeds = [int(seed) + (x if p.subseed_strength == 0 else 0) for x in range(len(p.all_prompts))]
if type(subseed) == list:
- all_subseeds = subseed
+ p.all_subseeds = subseed
else:
- all_subseeds = [int(subseed) + x for x in range(len(all_prompts))]
+ p.all_subseeds = [int(subseed) + x for x in range(len(p.all_prompts))]
def infotext(iteration=0, position_in_batch=0):
- return create_infotext(p, all_prompts, all_seeds, all_subseeds, comments, iteration, position_in_batch)
+ return create_infotext(p, p.all_prompts, p.all_seeds, p.all_subseeds, comments, iteration, position_in_batch)
if os.path.exists(cmd_opts.embeddings_dir) and not p.do_not_reload_embeddings:
model_hijack.embedding_db.load_textual_inversion_embeddings()
+ if p.scripts is not None:
+ p.scripts.run_alwayson_scripts(p)
+
infotexts = []
output_images = []
with torch.no_grad(), p.sd_model.ema_scope():
with devices.autocast():
- p.init(all_prompts, all_seeds, all_subseeds)
+ p.init(p.all_prompts, p.all_seeds, p.all_subseeds)
if state.job_count == -1:
state.job_count = p.n_iter
@@ -387,15 +415,13 @@ def process_images(p: StableDiffusionProcessing) -> Processed:
if state.interrupted:
break
- prompts = all_prompts[n * p.batch_size:(n + 1) * p.batch_size]
- seeds = all_seeds[n * p.batch_size:(n + 1) * p.batch_size]
- subseeds = all_subseeds[n * p.batch_size:(n + 1) * p.batch_size]
+ prompts = p.all_prompts[n * p.batch_size:(n + 1) * p.batch_size]
+ seeds = p.all_seeds[n * p.batch_size:(n + 1) * p.batch_size]
+ subseeds = p.all_subseeds[n * p.batch_size:(n + 1) * p.batch_size]
if (len(prompts) == 0):
break
- #uc = p.sd_model.get_learned_conditioning(len(prompts) * [p.negative_prompt])
- #c = p.sd_model.get_learned_conditioning(prompts)
with devices.autocast():
uc = prompt_parser.get_learned_conditioning(shared.sd_model, len(prompts) * [p.negative_prompt], p.steps)
c = prompt_parser.get_multicond_learned_conditioning(shared.sd_model, prompts, p.steps)
@@ -442,22 +468,11 @@ def process_images(p: StableDiffusionProcessing) -> Processed:
if p.color_corrections is not None and i < len(p.color_corrections):
if opts.save and not p.do_not_save_samples and opts.save_images_before_color_correction:
- images.save_image(image, p.outpath_samples, "", seeds[i], prompts[i], opts.samples_format, info=infotext(n, i), p=p, suffix="-before-color-correction")
+ image_without_cc = apply_overlay(image, p.paste_to, i, p.overlay_images)
+ images.save_image(image_without_cc, p.outpath_samples, "", seeds[i], prompts[i], opts.samples_format, info=infotext(n, i), p=p, suffix="-before-color-correction")
image = apply_color_correction(p.color_corrections[i], image)
- if p.overlay_images is not None and i < len(p.overlay_images):
- overlay = p.overlay_images[i]
-
- if p.paste_to is not None:
- x, y, w, h = p.paste_to
- base_image = Image.new('RGBA', (overlay.width, overlay.height))
- image = images.resize_image(1, image, w, h)
- base_image.paste(image, (x, y))
- image = base_image
-
- image = image.convert('RGBA')
- image.alpha_composite(overlay)
- image = image.convert('RGB')
+ image = apply_overlay(image, p.paste_to, i, p.overlay_images)
if opts.samples_save and not p.do_not_save_samples:
images.save_image(image, p.outpath_samples, "", seeds[i], prompts[i], opts.samples_format, info=infotext(n, i), p=p)
@@ -490,10 +505,10 @@ def process_images(p: StableDiffusionProcessing) -> Processed:
index_of_first_image = 1
if opts.grid_save:
- images.save_image(grid, p.outpath_grids, "grid", all_seeds[0], all_prompts[0], opts.grid_format, info=infotext(), short_filename=not opts.grid_extended_filename, p=p, grid=True)
+ images.save_image(grid, p.outpath_grids, "grid", p.all_seeds[0], p.all_prompts[0], opts.grid_format, info=infotext(), short_filename=not opts.grid_extended_filename, p=p, grid=True)
devices.torch_gc()
- return Processed(p, output_images, all_seeds[0], infotext() + "".join(["\n\n" + x for x in comments]), subseed=all_subseeds[0], all_prompts=all_prompts, all_seeds=all_seeds, all_subseeds=all_subseeds, index_of_first_image=index_of_first_image, infotexts=infotexts)
+ return Processed(p, output_images, p.all_seeds[0], infotext() + "".join(["\n\n" + x for x in comments]), subseed=p.all_subseeds[0], all_prompts=p.all_prompts, all_seeds=p.all_seeds, all_subseeds=p.all_subseeds, index_of_first_image=index_of_first_image, infotexts=infotexts)
class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing):
@@ -515,6 +530,8 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing):
else:
state.job_count = state.job_count * 2
+ self.extra_generation_params["First pass size"] = f"{self.firstphase_width}x{self.firstphase_height}"
+
if self.firstphase_width == 0 or self.firstphase_height == 0:
desired_pixel_count = 512 * 512
actual_pixel_count = self.width * self.height
@@ -536,21 +553,40 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing):
firstphase_width_truncated = self.firstphase_height * self.width / self.height
firstphase_height_truncated = self.firstphase_height
- self.extra_generation_params["First pass size"] = f"{self.firstphase_width}x{self.firstphase_height}"
self.truncate_x = int(self.firstphase_width - firstphase_width_truncated) // opt_f
self.truncate_y = int(self.firstphase_height - firstphase_height_truncated) // opt_f
+ def create_dummy_mask(self, x, width=None, height=None):
+ if self.sampler.conditioning_key in {'hybrid', 'concat'}:
+ height = height or self.height
+ width = width or self.width
+
+ # The "masked-image" in this case will just be all zeros since the entire image is masked.
+ image_conditioning = torch.zeros(x.shape[0], 3, height, width, device=x.device)
+ image_conditioning = self.sd_model.get_first_stage_encoding(self.sd_model.encode_first_stage(image_conditioning))
+
+ # Add the fake full 1s mask to the first dimension.
+ image_conditioning = torch.nn.functional.pad(image_conditioning, (0, 0, 0, 0, 1, 0), value=1.0)
+ image_conditioning = image_conditioning.to(x.dtype)
+
+ else:
+ # Dummy zero conditioning if we're not using inpainting model.
+ # Still takes up a bit of memory, but no encoder call.
+ # Pretty sure we can just make this a 1x1 image since its not going to be used besides its batch size.
+ image_conditioning = torch.zeros(x.shape[0], 5, 1, 1, dtype=x.dtype, device=x.device)
+
+ return image_conditioning
def sample(self, conditioning, unconditional_conditioning, seeds, subseeds, subseed_strength):
self.sampler = sd_samplers.create_sampler_with_index(sd_samplers.samplers, self.sampler_index, self.sd_model)
if not self.enable_hr:
x = create_random_tensors([opt_C, self.height // opt_f, self.width // opt_f], seeds=seeds, subseeds=subseeds, subseed_strength=self.subseed_strength, seed_resize_from_h=self.seed_resize_from_h, seed_resize_from_w=self.seed_resize_from_w, p=self)
- samples = self.sampler.sample(self, x, conditioning, unconditional_conditioning)
+ samples = self.sampler.sample(self, x, conditioning, unconditional_conditioning, image_conditioning=self.create_dummy_mask(x))
return samples
x = create_random_tensors([opt_C, self.firstphase_height // opt_f, self.firstphase_width // opt_f], seeds=seeds, subseeds=subseeds, subseed_strength=self.subseed_strength, seed_resize_from_h=self.seed_resize_from_h, seed_resize_from_w=self.seed_resize_from_w, p=self)
- samples = self.sampler.sample(self, x, conditioning, unconditional_conditioning)
+ samples = self.sampler.sample(self, x, conditioning, unconditional_conditioning, image_conditioning=self.create_dummy_mask(x, self.firstphase_width, self.firstphase_height))
samples = samples[:, :, self.truncate_y//2:samples.shape[2]-self.truncate_y//2, self.truncate_x//2:samples.shape[3]-self.truncate_x//2]
@@ -587,7 +623,7 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing):
x = None
devices.torch_gc()
- samples = self.sampler.sample_img2img(self, samples, noise, conditioning, unconditional_conditioning, steps=self.steps)
+ samples = self.sampler.sample_img2img(self, samples, noise, conditioning, unconditional_conditioning, steps=self.steps, image_conditioning=self.create_dummy_mask(samples))
return samples
@@ -595,7 +631,7 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing):
class StableDiffusionProcessingImg2Img(StableDiffusionProcessing):
sampler = None
- def __init__(self, init_images=None, resize_mode=0, denoising_strength=0.75, mask=None, mask_blur=4, inpainting_fill=0, inpaint_full_res=True, inpaint_full_res_padding=0, inpainting_mask_invert=0, **kwargs):
+ def __init__(self, init_images: list=None, resize_mode: int=0, denoising_strength: float=0.75, mask: Any=None, mask_blur: int=4, inpainting_fill: int=0, inpaint_full_res: bool=True, inpaint_full_res_padding: int=0, inpainting_mask_invert: int=0, **kwargs):
super().__init__(**kwargs)
self.init_images = init_images
@@ -613,6 +649,7 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing):
self.inpainting_mask_invert = inpainting_mask_invert
self.mask = None
self.nmask = None
+ self.image_conditioning = None
def init(self, all_prompts, all_seeds, all_subseeds):
self.sampler = sd_samplers.create_sampler_with_index(sd_samplers.samplers_for_img2img, self.sampler_index, self.sd_model)
@@ -685,6 +722,10 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing):
batch_images = np.expand_dims(imgs[0], axis=0).repeat(self.batch_size, axis=0)
if self.overlay_images is not None:
self.overlay_images = self.overlay_images * self.batch_size
+
+ if self.color_corrections is not None and len(self.color_corrections) == 1:
+ self.color_corrections = self.color_corrections * self.batch_size
+
elif len(imgs) <= self.batch_size:
self.batch_size = len(imgs)
batch_images = np.array(imgs)
@@ -714,10 +755,39 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing):
elif self.inpainting_fill == 3:
self.init_latent = self.init_latent * self.mask
+ if self.sampler.conditioning_key in {'hybrid', 'concat'}:
+ if self.image_mask is not None:
+ conditioning_mask = np.array(self.image_mask.convert("L"))
+ conditioning_mask = conditioning_mask.astype(np.float32) / 255.0
+ conditioning_mask = torch.from_numpy(conditioning_mask[None, None])
+
+ # Inpainting model uses a discretized mask as input, so we round to either 1.0 or 0.0
+ conditioning_mask = torch.round(conditioning_mask)
+ else:
+ conditioning_mask = torch.ones(1, 1, *image.shape[-2:])
+
+ # Create another latent image, this time with a masked version of the original input.
+ conditioning_mask = conditioning_mask.to(image.device)
+ conditioning_image = image * (1.0 - conditioning_mask)
+ conditioning_image = self.sd_model.get_first_stage_encoding(self.sd_model.encode_first_stage(conditioning_image))
+
+ # Create the concatenated conditioning tensor to be fed to `c_concat`
+ conditioning_mask = torch.nn.functional.interpolate(conditioning_mask, size=self.init_latent.shape[-2:])
+ conditioning_mask = conditioning_mask.expand(conditioning_image.shape[0], -1, -1, -1)
+ self.image_conditioning = torch.cat([conditioning_mask, conditioning_image], dim=1)
+ self.image_conditioning = self.image_conditioning.to(shared.device).type(self.sd_model.dtype)
+ else:
+ self.image_conditioning = torch.zeros(
+ self.init_latent.shape[0], 5, 1, 1,
+ dtype=self.init_latent.dtype,
+ device=self.init_latent.device
+ )
+
+
def sample(self, conditioning, unconditional_conditioning, seeds, subseeds, subseed_strength):
x = create_random_tensors([opt_C, self.height // opt_f, self.width // opt_f], seeds=seeds, subseeds=subseeds, subseed_strength=self.subseed_strength, seed_resize_from_h=self.seed_resize_from_h, seed_resize_from_w=self.seed_resize_from_w, p=self)
- samples = self.sampler.sample_img2img(self, self.init_latent, x, conditioning, unconditional_conditioning)
+ samples = self.sampler.sample_img2img(self, self.init_latent, x, conditioning, unconditional_conditioning, image_conditioning=self.image_conditioning)
if self.mask is not None:
samples = samples * self.nmask + self.init_latent * self.mask
diff --git a/modules/script_callbacks.py b/modules/script_callbacks.py
new file mode 100644
index 00000000..dc520abc
--- /dev/null
+++ b/modules/script_callbacks.py
@@ -0,0 +1,100 @@
+import sys
+import traceback
+from collections import namedtuple
+import inspect
+
+
+def report_exception(c, job):
+ print(f"Error executing callback {job} for {c.script}", file=sys.stderr)
+ print(traceback.format_exc(), file=sys.stderr)
+
+
+ScriptCallback = namedtuple("ScriptCallback", ["script", "callback"])
+callbacks_model_loaded = []
+callbacks_ui_tabs = []
+callbacks_ui_settings = []
+callbacks_image_saved = []
+
+def clear_callbacks():
+ callbacks_model_loaded.clear()
+ callbacks_ui_tabs.clear()
+ callbacks_image_saved.clear()
+
+
+def model_loaded_callback(sd_model):
+ for c in callbacks_model_loaded:
+ try:
+ c.callback(sd_model)
+ except Exception:
+ report_exception(c, 'model_loaded_callback')
+
+
+def ui_tabs_callback():
+ res = []
+
+ for c in callbacks_ui_tabs:
+ try:
+ res += c.callback() or []
+ except Exception:
+ report_exception(c, 'ui_tabs_callback')
+
+ return res
+
+
+def ui_settings_callback():
+ for c in callbacks_ui_settings:
+ try:
+ c.callback()
+ except Exception:
+ report_exception(c, 'ui_settings_callback')
+
+
+def image_saved_callback(image, p, fullfn, txt_fullfn):
+ for c in callbacks_image_saved:
+ try:
+ c.callback(image, p, fullfn, txt_fullfn)
+ except Exception:
+ report_exception(c, 'image_saved_callback')
+
+
+def add_callback(callbacks, fun):
+ stack = [x for x in inspect.stack() if x.filename != __file__]
+ filename = stack[0].filename if len(stack) > 0 else 'unknown file'
+
+ callbacks.append(ScriptCallback(filename, fun))
+
+
+
+def on_model_loaded(callback):
+ """register a function to be called when the stable diffusion model is created; the model is
+ passed as an argument"""
+ add_callback(callbacks_model_loaded, callback)
+
+
+def on_ui_tabs(callback):
+ """register a function to be called when the UI is creating new tabs.
+ The function must either return a None, which means no new tabs to be added, or a list, where
+ each element is a tuple:
+ (gradio_component, title, elem_id)
+
+ gradio_component is a gradio component to be used for contents of the tab (usually gr.Blocks)
+ title is tab text displayed to user in the UI
+ elem_id is HTML id for the tab
+ """
+ add_callback(callbacks_ui_tabs, callback)
+
+
+def on_ui_settings(callback):
+ """register a function to be called before UI settings are populated; add your settings
+ by using shared.opts.add_option(shared.OptionInfo(...)) """
+ add_callback(callbacks_ui_settings, callback)
+
+
+def on_save_imaged(callback):
+ """register a function to be called after modules.images.save_image is called.
+ The callback is called with three arguments:
+ - p - procesing object (or a dummy object with same fields if the image is saved using save button)
+ - fullfn - image filename
+ - txt_fullfn - text file with parameters; may be None
+ """
+ add_callback(callbacks_image_saved, callback)
diff --git a/modules/scripts.py b/modules/scripts.py
index 1039fa9c..9323af3e 100644
--- a/modules/scripts.py
+++ b/modules/scripts.py
@@ -1,86 +1,175 @@
import os
import sys
import traceback
+from collections import namedtuple
import modules.ui as ui
import gradio as gr
from modules.processing import StableDiffusionProcessing
-from modules import shared
+from modules import shared, paths, script_callbacks
+
+AlwaysVisible = object()
+
class Script:
filename = None
args_from = None
args_to = None
+ alwayson = False
+
+ infotext_fields = None
+ """if set in ui(), this is a list of pairs of gradio component + text; the text will be used when
+ parsing infotext to set the value for the component; see ui.py's txt2img_paste_fields for an example
+ """
- # The title of the script. This is what will be displayed in the dropdown menu.
def title(self):
+ """this function should return the title of the script. This is what will be displayed in the dropdown menu."""
+
raise NotImplementedError()
- # How the script is displayed in the UI. See https://gradio.app/docs/#components
- # for the different UI components you can use and how to create them.
- # Most UI components can return a value, such as a boolean for a checkbox.
- # The returned values are passed to the run method as parameters.
def ui(self, is_img2img):
+ """this function should create gradio UI elements. See https://gradio.app/docs/#components
+ The return value should be an array of all components that are used in processing.
+ Values of those returned componenbts will be passed to run() and process() functions.
+ """
+
pass
- # Determines when the script should be shown in the dropdown menu via the
- # returned value. As an example:
- # is_img2img is True if the current tab is img2img, and False if it is txt2img.
- # Thus, return is_img2img to only show the script on the img2img tab.
def show(self, is_img2img):
+ """
+ is_img2img is True if this function is called for the img2img interface, and Fasle otherwise
+
+ This function should return:
+ - False if the script should not be shown in UI at all
+ - True if the script should be shown in UI if it's scelected in the scripts drowpdown
+ - script.AlwaysVisible if the script should be shown in UI at all times
+ """
+
return True
- # This is where the additional processing is implemented. The parameters include
- # self, the model object "p" (a StableDiffusionProcessing class, see
- # processing.py), and the parameters returned by the ui method.
- # Custom functions can be defined here, and additional libraries can be imported
- # to be used in processing. The return value should be a Processed object, which is
- # what is returned by the process_images method.
- def run(self, *args):
+ def run(self, p, *args):
+ """
+ This function is called if the script has been selected in the script dropdown.
+ It must do all processing and return the Processed object with results, same as
+ one returned by processing.process_images.
+
+ Usually the processing is done by calling the processing.process_images function.
+
+ args contains all values returned by components from ui()
+ """
+
raise NotImplementedError()
- # The description method is currently unused.
- # To add a description that appears when hovering over the title, amend the "titles"
- # dict in script.js to include the script title (returned by title) as a key, and
- # your description as the value.
+ def process(self, p, *args):
+ """
+ This function is called before processing begins for AlwaysVisible scripts.
+ scripts. You can modify the processing object (p) here, inject hooks, etc.
+ """
+
+ pass
+
def describe(self):
+ """unused"""
return ""
+current_basedir = paths.script_path
+
+
+def basedir():
+ """returns the base directory for the current script. For scripts in the main scripts directory,
+ this is the main directory (where webui.py resides), and for scripts in extensions directory
+ (ie extensions/aesthetic/script/aesthetic.py), this is extension's directory (extensions/aesthetic)
+ """
+ return current_basedir
+
+
scripts_data = []
+ScriptFile = namedtuple("ScriptFile", ["basedir", "filename", "path"])
+ScriptClassData = namedtuple("ScriptClassData", ["script_class", "path", "basedir"])
-def load_scripts(basedir):
- if not os.path.exists(basedir):
- return
+def list_scripts(scriptdirname, extension):
+ scripts_list = []
- for filename in sorted(os.listdir(basedir)):
- path = os.path.join(basedir, filename)
+ basedir = os.path.join(paths.script_path, scriptdirname)
+ if os.path.exists(basedir):
+ for filename in sorted(os.listdir(basedir)):
+ scripts_list.append(ScriptFile(paths.script_path, filename, os.path.join(basedir, filename)))
- if os.path.splitext(path)[1].lower() != '.py':
- continue
+ extdir = os.path.join(paths.script_path, "extensions")
+ if os.path.exists(extdir):
+ for dirname in sorted(os.listdir(extdir)):
+ dirpath = os.path.join(extdir, dirname)
+ scriptdirpath = os.path.join(dirpath, scriptdirname)
+
+ if not os.path.isdir(scriptdirpath):
+ continue
+
+ for filename in sorted(os.listdir(scriptdirpath)):
+ scripts_list.append(ScriptFile(dirpath, filename, os.path.join(scriptdirpath, filename)))
+
+ scripts_list = [x for x in scripts_list if os.path.splitext(x.path)[1].lower() == extension and os.path.isfile(x.path)]
+
+ return scripts_list
+
+
+def list_files_with_name(filename):
+ res = []
+
+ dirs = [paths.script_path]
+
+ extdir = os.path.join(paths.script_path, "extensions")
+ if os.path.exists(extdir):
+ dirs += [os.path.join(extdir, d) for d in sorted(os.listdir(extdir))]
- if not os.path.isfile(path):
+ for dirpath in dirs:
+ if not os.path.isdir(dirpath):
continue
+ path = os.path.join(dirpath, filename)
+ if os.path.isfile(filename):
+ res.append(path)
+
+ return res
+
+
+def load_scripts():
+ global current_basedir
+ scripts_data.clear()
+ script_callbacks.clear_callbacks()
+
+ scripts_list = list_scripts("scripts", ".py")
+
+ syspath = sys.path
+
+ for scriptfile in sorted(scripts_list):
try:
- with open(path, "r", encoding="utf8") as file:
+ if scriptfile.basedir != paths.script_path:
+ sys.path = [scriptfile.basedir] + sys.path
+ current_basedir = scriptfile.basedir
+
+ with open(scriptfile.path, "r", encoding="utf8") as file:
text = file.read()
from types import ModuleType
- compiled = compile(text, path, 'exec')
- module = ModuleType(filename)
+ compiled = compile(text, scriptfile.path, 'exec')
+ module = ModuleType(scriptfile.filename)
exec(compiled, module.__dict__)
for key, script_class in module.__dict__.items():
if type(script_class) == type and issubclass(script_class, Script):
- scripts_data.append((script_class, path))
+ scripts_data.append(ScriptClassData(script_class, scriptfile.path, scriptfile.basedir))
except Exception:
- print(f"Error loading script: {filename}", file=sys.stderr)
+ print(f"Error loading script: {scriptfile.filename}", file=sys.stderr)
print(traceback.format_exc(), file=sys.stderr)
+ finally:
+ sys.path = syspath
+ current_basedir = paths.script_path
+
def wrap_call(func, filename, funcname, *args, default=None, **kwargs):
try:
@@ -96,56 +185,80 @@ def wrap_call(func, filename, funcname, *args, default=None, **kwargs):
class ScriptRunner:
def __init__(self):
self.scripts = []
+ self.selectable_scripts = []
+ self.alwayson_scripts = []
self.titles = []
+ self.infotext_fields = []
def setup_ui(self, is_img2img):
- for script_class, path in scripts_data:
+ for script_class, path, basedir in scripts_data:
script = script_class()
script.filename = path
- if not script.show(is_img2img):
- continue
+ visibility = script.show(is_img2img)
- self.scripts.append(script)
+ if visibility == AlwaysVisible:
+ self.scripts.append(script)
+ self.alwayson_scripts.append(script)
+ script.alwayson = True
- self.titles = [wrap_call(script.title, script.filename, "title") or f"{script.filename} [error]" for script in self.scripts]
+ elif visibility:
+ self.scripts.append(script)
+ self.selectable_scripts.append(script)
- dropdown = gr.Dropdown(label="Script", choices=["None"] + self.titles, value="None", type="index")
- dropdown.save_to_config = True
- inputs = [dropdown]
+ self.titles = [wrap_call(script.title, script.filename, "title") or f"{script.filename} [error]" for script in self.selectable_scripts]
+
+ inputs = [None]
+ inputs_alwayson = [True]
- for script in self.scripts:
+ def create_script_ui(script, inputs, inputs_alwayson):
script.args_from = len(inputs)
script.args_to = len(inputs)
controls = wrap_call(script.ui, script.filename, "ui", is_img2img)
if controls is None:
- continue
+ return
for control in controls:
control.custom_script_source = os.path.basename(script.filename)
- control.visible = False
+ if not script.alwayson:
+ control.visible = False
+
+ if script.infotext_fields is not None:
+ self.infotext_fields += script.infotext_fields
inputs += controls
+ inputs_alwayson += [script.alwayson for _ in controls]
script.args_to = len(inputs)
+ for script in self.alwayson_scripts:
+ with gr.Group():
+ create_script_ui(script, inputs, inputs_alwayson)
+
+ dropdown = gr.Dropdown(label="Script", choices=["None"] + self.titles, value="None", type="index")
+ dropdown.save_to_config = True
+ inputs[0] = dropdown
+
+ for script in self.selectable_scripts:
+ create_script_ui(script, inputs, inputs_alwayson)
+
def select_script(script_index):
- if 0 < script_index <= len(self.scripts):
- script = self.scripts[script_index-1]
+ if 0 < script_index <= len(self.selectable_scripts):
+ script = self.selectable_scripts[script_index-1]
args_from = script.args_from
args_to = script.args_to
else:
args_from = 0
args_to = 0
- return [ui.gr_show(True if i == 0 else args_from <= i < args_to) for i in range(len(inputs))]
+ return [ui.gr_show(True if i == 0 else args_from <= i < args_to or is_alwayson) for i, is_alwayson in enumerate(inputs_alwayson)]
def init_field(title):
if title == 'None':
return
script_index = self.titles.index(title)
- script = self.scripts[script_index]
+ script = self.selectable_scripts[script_index]
for i in range(script.args_from, script.args_to):
inputs[i].visible = True
@@ -164,7 +277,7 @@ class ScriptRunner:
if script_index == 0:
return None
- script = self.scripts[script_index-1]
+ script = self.selectable_scripts[script_index-1]
if script is None:
return None
@@ -176,7 +289,16 @@ class ScriptRunner:
return processed
- def reload_sources(self):
+ def run_alwayson_scripts(self, p):
+ for script in self.alwayson_scripts:
+ try:
+ script_args = p.script_args[script.args_from:script.args_to]
+ script.process(p, *script_args)
+ except Exception:
+ print(f"Error running alwayson script: {script.filename}", file=sys.stderr)
+ print(traceback.format_exc(), file=sys.stderr)
+
+ def reload_sources(self, cache):
for si, script in list(enumerate(self.scripts)):
with open(script.filename, "r", encoding="utf8") as file:
args_from = script.args_from
@@ -186,9 +308,12 @@ class ScriptRunner:
from types import ModuleType
- compiled = compile(text, filename, 'exec')
- module = ModuleType(script.filename)
- exec(compiled, module.__dict__)
+ module = cache.get(filename, None)
+ if module is None:
+ compiled = compile(text, filename, 'exec')
+ module = ModuleType(script.filename)
+ exec(compiled, module.__dict__)
+ cache[filename] = module
for key, script_class in module.__dict__.items():
if type(script_class) == type and issubclass(script_class, Script):
@@ -197,19 +322,22 @@ class ScriptRunner:
self.scripts[si].args_from = args_from
self.scripts[si].args_to = args_to
+
scripts_txt2img = ScriptRunner()
scripts_img2img = ScriptRunner()
+
def reload_script_body_only():
- scripts_txt2img.reload_sources()
- scripts_img2img.reload_sources()
+ cache = {}
+ scripts_txt2img.reload_sources(cache)
+ scripts_img2img.reload_sources(cache)
-def reload_scripts(basedir):
+def reload_scripts():
global scripts_txt2img, scripts_img2img
- scripts_data.clear()
- load_scripts(basedir)
+ load_scripts()
scripts_txt2img = ScriptRunner()
scripts_img2img = ScriptRunner()
+
diff --git a/modules/scunet_model.py b/modules/scunet_model.py
index 36a996bf..59532274 100644
--- a/modules/scunet_model.py
+++ b/modules/scunet_model.py
@@ -54,9 +54,8 @@ class UpscalerScuNET(modules.upscaler.Upscaler):
img = img[:, :, ::-1]
img = np.moveaxis(img, 2, 0) / 255
img = torch.from_numpy(img).float()
- img = img.unsqueeze(0).to(device)
+ img = devices.mps_contiguous_to(img.unsqueeze(0), device)
- img = img.to(device)
with torch.no_grad():
output = model(img)
output = output.squeeze().float().cpu().clamp_(0, 1).numpy()
diff --git a/modules/sd_hijack.py b/modules/sd_hijack.py
index 984b35c4..0f10828e 100644
--- a/modules/sd_hijack.py
+++ b/modules/sd_hijack.py
@@ -19,6 +19,7 @@ attention_CrossAttention_forward = ldm.modules.attention.CrossAttention.forward
diffusionmodules_model_nonlinearity = ldm.modules.diffusionmodules.model.nonlinearity
diffusionmodules_model_AttnBlock_forward = ldm.modules.diffusionmodules.model.AttnBlock.forward
+
def apply_optimizations():
undo_optimizations()
@@ -167,11 +168,11 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module):
remade_tokens = remade_tokens[:last_comma]
length = len(remade_tokens)
-
+
rem = int(math.ceil(length / 75)) * 75 - length
remade_tokens += [id_end] * rem + reloc_tokens
multipliers = multipliers[:last_comma] + [1.0] * rem + reloc_mults
-
+
if embedding is None:
remade_tokens.append(token)
multipliers.append(weight)
@@ -223,7 +224,6 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module):
return batch_multipliers, remade_batch_tokens, used_custom_terms, hijack_comments, hijack_fixes, token_count
-
def process_text_old(self, text):
id_start = self.wrapped.tokenizer.bos_token_id
id_end = self.wrapped.tokenizer.eos_token_id
@@ -280,7 +280,7 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module):
token_count = len(remade_tokens)
remade_tokens = remade_tokens + [id_end] * (maxlen - 2 - len(remade_tokens))
- remade_tokens = [id_start] + remade_tokens[0:maxlen-2] + [id_end]
+ remade_tokens = [id_start] + remade_tokens[0:maxlen - 2] + [id_end]
cache[tuple_tokens] = (remade_tokens, fixes, multipliers)
multipliers = multipliers + [1.0] * (maxlen - 2 - len(multipliers))
@@ -290,7 +290,7 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module):
hijack_fixes.append(fixes)
batch_multipliers.append(multipliers)
return batch_multipliers, remade_batch_tokens, used_custom_terms, hijack_comments, hijack_fixes, token_count
-
+
def forward(self, text):
use_old = opts.use_old_emphasis_implementation
if use_old:
@@ -302,11 +302,11 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module):
if len(used_custom_terms) > 0:
self.hijack.comments.append("Used embeddings: " + ", ".join([f'{word} [{checksum}]' for word, checksum in used_custom_terms]))
-
+
if use_old:
self.hijack.fixes = hijack_fixes
return self.process_tokens(remade_batch_tokens, batch_multipliers)
-
+
z = None
i = 0
while max(map(len, remade_batch_tokens)) != 0:
@@ -320,7 +320,7 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module):
if fix[0] == i:
fixes.append(fix[1])
self.hijack.fixes.append(fixes)
-
+
tokens = []
multipliers = []
for j in range(len(remade_batch_tokens)):
@@ -333,19 +333,18 @@ class FrozenCLIPEmbedderWithCustomWords(torch.nn.Module):
z1 = self.process_tokens(tokens, multipliers)
z = z1 if z is None else torch.cat((z, z1), axis=-2)
-
+
remade_batch_tokens = rem_tokens
batch_multipliers = rem_multipliers
i += 1
-
+
return z
-
-
+
def process_tokens(self, remade_batch_tokens, batch_multipliers):
if not opts.use_old_emphasis_implementation:
remade_batch_tokens = [[self.wrapped.tokenizer.bos_token_id] + x[:75] + [self.wrapped.tokenizer.eos_token_id] for x in remade_batch_tokens]
batch_multipliers = [[1.0] + x[:75] + [1.0] for x in batch_multipliers]
-
+
tokens = torch.asarray(remade_batch_tokens).to(device)
outputs = self.wrapped.transformer(input_ids=tokens, output_hidden_states=-opts.CLIP_stop_at_last_layers)
@@ -385,8 +384,8 @@ class EmbeddingsWithFixes(torch.nn.Module):
for fixes, tensor in zip(batch_fixes, inputs_embeds):
for offset, embedding in fixes:
emb = embedding.vec
- emb_len = min(tensor.shape[0]-offset-1, emb.shape[0])
- tensor = torch.cat([tensor[0:offset+1], emb[0:emb_len], tensor[offset+1+emb_len:]])
+ emb_len = min(tensor.shape[0] - offset - 1, emb.shape[0])
+ tensor = torch.cat([tensor[0:offset + 1], emb[0:emb_len], tensor[offset + 1 + emb_len:]])
vecs.append(tensor)
diff --git a/modules/sd_hijack_inpainting.py b/modules/sd_hijack_inpainting.py
new file mode 100644
index 00000000..fd92a335
--- /dev/null
+++ b/modules/sd_hijack_inpainting.py
@@ -0,0 +1,331 @@
+import torch
+
+from einops import repeat
+from omegaconf import ListConfig
+
+import ldm.models.diffusion.ddpm
+import ldm.models.diffusion.ddim
+import ldm.models.diffusion.plms
+
+from ldm.models.diffusion.ddpm import LatentDiffusion
+from ldm.models.diffusion.plms import PLMSSampler
+from ldm.models.diffusion.ddim import DDIMSampler, noise_like
+
+# =================================================================================================
+# Monkey patch DDIMSampler methods from RunwayML repo directly.
+# Adapted from:
+# https://github.com/runwayml/stable-diffusion/blob/main/ldm/models/diffusion/ddim.py
+# =================================================================================================
+@torch.no_grad()
+def sample_ddim(self,
+ S,
+ batch_size,
+ shape,
+ conditioning=None,
+ callback=None,
+ normals_sequence=None,
+ img_callback=None,
+ quantize_x0=False,
+ eta=0.,
+ mask=None,
+ x0=None,
+ temperature=1.,
+ noise_dropout=0.,
+ score_corrector=None,
+ corrector_kwargs=None,
+ verbose=True,
+ x_T=None,
+ log_every_t=100,
+ unconditional_guidance_scale=1.,
+ unconditional_conditioning=None,
+ # this has to come in the same format as the conditioning, # e.g. as encoded tokens, ...
+ **kwargs
+ ):
+ if conditioning is not None:
+ if isinstance(conditioning, dict):
+ ctmp = conditioning[list(conditioning.keys())[0]]
+ while isinstance(ctmp, list):
+ ctmp = ctmp[0]
+ cbs = ctmp.shape[0]
+ if cbs != batch_size:
+ print(f"Warning: Got {cbs} conditionings but batch-size is {batch_size}")
+ else:
+ if conditioning.shape[0] != batch_size:
+ print(f"Warning: Got {conditioning.shape[0]} conditionings but batch-size is {batch_size}")
+
+ self.make_schedule(ddim_num_steps=S, ddim_eta=eta, verbose=verbose)
+ # sampling
+ C, H, W = shape
+ size = (batch_size, C, H, W)
+ print(f'Data shape for DDIM sampling is {size}, eta {eta}')
+
+ samples, intermediates = self.ddim_sampling(conditioning, size,
+ callback=callback,
+ img_callback=img_callback,
+ quantize_denoised=quantize_x0,
+ mask=mask, x0=x0,
+ ddim_use_original_steps=False,
+ noise_dropout=noise_dropout,
+ temperature=temperature,
+ score_corrector=score_corrector,
+ corrector_kwargs=corrector_kwargs,
+ x_T=x_T,
+ log_every_t=log_every_t,
+ unconditional_guidance_scale=unconditional_guidance_scale,
+ unconditional_conditioning=unconditional_conditioning,
+ )
+ return samples, intermediates
+
+@torch.no_grad()
+def p_sample_ddim(self, x, c, t, index, repeat_noise=False, use_original_steps=False, quantize_denoised=False,
+ temperature=1., noise_dropout=0., score_corrector=None, corrector_kwargs=None,
+ unconditional_guidance_scale=1., unconditional_conditioning=None):
+ b, *_, device = *x.shape, x.device
+
+ if unconditional_conditioning is None or unconditional_guidance_scale == 1.:
+ e_t = self.model.apply_model(x, t, c)
+ else:
+ x_in = torch.cat([x] * 2)
+ t_in = torch.cat([t] * 2)
+ if isinstance(c, dict):
+ assert isinstance(unconditional_conditioning, dict)
+ c_in = dict()
+ for k in c:
+ if isinstance(c[k], list):
+ c_in[k] = [
+ torch.cat([unconditional_conditioning[k][i], c[k][i]])
+ for i in range(len(c[k]))
+ ]
+ else:
+ c_in[k] = torch.cat([unconditional_conditioning[k], c[k]])
+ else:
+ c_in = torch.cat([unconditional_conditioning, c])
+ e_t_uncond, e_t = self.model.apply_model(x_in, t_in, c_in).chunk(2)
+ e_t = e_t_uncond + unconditional_guidance_scale * (e_t - e_t_uncond)
+
+ if score_corrector is not None:
+ assert self.model.parameterization == "eps"
+ e_t = score_corrector.modify_score(self.model, e_t, x, t, c, **corrector_kwargs)
+
+ alphas = self.model.alphas_cumprod if use_original_steps else self.ddim_alphas
+ alphas_prev = self.model.alphas_cumprod_prev if use_original_steps else self.ddim_alphas_prev
+ sqrt_one_minus_alphas = self.model.sqrt_one_minus_alphas_cumprod if use_original_steps else self.ddim_sqrt_one_minus_alphas
+ sigmas = self.model.ddim_sigmas_for_original_num_steps if use_original_steps else self.ddim_sigmas
+ # select parameters corresponding to the currently considered timestep
+ a_t = torch.full((b, 1, 1, 1), alphas[index], device=device)
+ a_prev = torch.full((b, 1, 1, 1), alphas_prev[index], device=device)
+ sigma_t = torch.full((b, 1, 1, 1), sigmas[index], device=device)
+ sqrt_one_minus_at = torch.full((b, 1, 1, 1), sqrt_one_minus_alphas[index],device=device)
+
+ # current prediction for x_0
+ pred_x0 = (x - sqrt_one_minus_at * e_t) / a_t.sqrt()
+ if quantize_denoised:
+ pred_x0, _, *_ = self.model.first_stage_model.quantize(pred_x0)
+ # direction pointing to x_t
+ dir_xt = (1. - a_prev - sigma_t**2).sqrt() * e_t
+ noise = sigma_t * noise_like(x.shape, device, repeat_noise) * temperature
+ if noise_dropout > 0.:
+ noise = torch.nn.functional.dropout(noise, p=noise_dropout)
+ x_prev = a_prev.sqrt() * pred_x0 + dir_xt + noise
+ return x_prev, pred_x0
+
+
+# =================================================================================================
+# Monkey patch PLMSSampler methods.
+# This one was not actually patched correctly in the RunwayML repo, but we can replicate the changes.
+# Adapted from:
+# https://github.com/CompVis/stable-diffusion/blob/main/ldm/models/diffusion/plms.py
+# =================================================================================================
+@torch.no_grad()
+def sample_plms(self,
+ S,
+ batch_size,
+ shape,
+ conditioning=None,
+ callback=None,
+ normals_sequence=None,
+ img_callback=None,
+ quantize_x0=False,
+ eta=0.,
+ mask=None,
+ x0=None,
+ temperature=1.,
+ noise_dropout=0.,
+ score_corrector=None,
+ corrector_kwargs=None,
+ verbose=True,
+ x_T=None,
+ log_every_t=100,
+ unconditional_guidance_scale=1.,
+ unconditional_conditioning=None,
+ # this has to come in the same format as the conditioning, # e.g. as encoded tokens, ...
+ **kwargs
+ ):
+ if conditioning is not None:
+ if isinstance(conditioning, dict):
+ ctmp = conditioning[list(conditioning.keys())[0]]
+ while isinstance(ctmp, list):
+ ctmp = ctmp[0]
+ cbs = ctmp.shape[0]
+ if cbs != batch_size:
+ print(f"Warning: Got {cbs} conditionings but batch-size is {batch_size}")
+ else:
+ if conditioning.shape[0] != batch_size:
+ print(f"Warning: Got {conditioning.shape[0]} conditionings but batch-size is {batch_size}")
+
+ self.make_schedule(ddim_num_steps=S, ddim_eta=eta, verbose=verbose)
+ # sampling
+ C, H, W = shape
+ size = (batch_size, C, H, W)
+ print(f'Data shape for PLMS sampling is {size}')
+
+ samples, intermediates = self.plms_sampling(conditioning, size,
+ callback=callback,
+ img_callback=img_callback,
+ quantize_denoised=quantize_x0,
+ mask=mask, x0=x0,
+ ddim_use_original_steps=False,
+ noise_dropout=noise_dropout,
+ temperature=temperature,
+ score_corrector=score_corrector,
+ corrector_kwargs=corrector_kwargs,
+ x_T=x_T,
+ log_every_t=log_every_t,
+ unconditional_guidance_scale=unconditional_guidance_scale,
+ unconditional_conditioning=unconditional_conditioning,
+ )
+ return samples, intermediates
+
+
+@torch.no_grad()
+def p_sample_plms(self, x, c, t, index, repeat_noise=False, use_original_steps=False, quantize_denoised=False,
+ temperature=1., noise_dropout=0., score_corrector=None, corrector_kwargs=None,
+ unconditional_guidance_scale=1., unconditional_conditioning=None, old_eps=None, t_next=None):
+ b, *_, device = *x.shape, x.device
+
+ def get_model_output(x, t):
+ if unconditional_conditioning is None or unconditional_guidance_scale == 1.:
+ e_t = self.model.apply_model(x, t, c)
+ else:
+ x_in = torch.cat([x] * 2)
+ t_in = torch.cat([t] * 2)
+
+ if isinstance(c, dict):
+ assert isinstance(unconditional_conditioning, dict)
+ c_in = dict()
+ for k in c:
+ if isinstance(c[k], list):
+ c_in[k] = [
+ torch.cat([unconditional_conditioning[k][i], c[k][i]])
+ for i in range(len(c[k]))
+ ]
+ else:
+ c_in[k] = torch.cat([unconditional_conditioning[k], c[k]])
+ else:
+ c_in = torch.cat([unconditional_conditioning, c])
+
+ e_t_uncond, e_t = self.model.apply_model(x_in, t_in, c_in).chunk(2)
+ e_t = e_t_uncond + unconditional_guidance_scale * (e_t - e_t_uncond)
+
+ if score_corrector is not None:
+ assert self.model.parameterization == "eps"
+ e_t = score_corrector.modify_score(self.model, e_t, x, t, c, **corrector_kwargs)
+
+ return e_t
+
+ alphas = self.model.alphas_cumprod if use_original_steps else self.ddim_alphas
+ alphas_prev = self.model.alphas_cumprod_prev if use_original_steps else self.ddim_alphas_prev
+ sqrt_one_minus_alphas = self.model.sqrt_one_minus_alphas_cumprod if use_original_steps else self.ddim_sqrt_one_minus_alphas
+ sigmas = self.model.ddim_sigmas_for_original_num_steps if use_original_steps else self.ddim_sigmas
+
+ def get_x_prev_and_pred_x0(e_t, index):
+ # select parameters corresponding to the currently considered timestep
+ a_t = torch.full((b, 1, 1, 1), alphas[index], device=device)
+ a_prev = torch.full((b, 1, 1, 1), alphas_prev[index], device=device)
+ sigma_t = torch.full((b, 1, 1, 1), sigmas[index], device=device)
+ sqrt_one_minus_at = torch.full((b, 1, 1, 1), sqrt_one_minus_alphas[index],device=device)
+
+ # current prediction for x_0
+ pred_x0 = (x - sqrt_one_minus_at * e_t) / a_t.sqrt()
+ if quantize_denoised:
+ pred_x0, _, *_ = self.model.first_stage_model.quantize(pred_x0)
+ # direction pointing to x_t
+ dir_xt = (1. - a_prev - sigma_t**2).sqrt() * e_t
+ noise = sigma_t * noise_like(x.shape, device, repeat_noise) * temperature
+ if noise_dropout > 0.:
+ noise = torch.nn.functional.dropout(noise, p=noise_dropout)
+ x_prev = a_prev.sqrt() * pred_x0 + dir_xt + noise
+ return x_prev, pred_x0
+
+ e_t = get_model_output(x, t)
+ if len(old_eps) == 0:
+ # Pseudo Improved Euler (2nd order)
+ x_prev, pred_x0 = get_x_prev_and_pred_x0(e_t, index)
+ e_t_next = get_model_output(x_prev, t_next)
+ e_t_prime = (e_t + e_t_next) / 2
+ elif len(old_eps) == 1:
+ # 2nd order Pseudo Linear Multistep (Adams-Bashforth)
+ e_t_prime = (3 * e_t - old_eps[-1]) / 2
+ elif len(old_eps) == 2:
+ # 3nd order Pseudo Linear Multistep (Adams-Bashforth)
+ e_t_prime = (23 * e_t - 16 * old_eps[-1] + 5 * old_eps[-2]) / 12
+ elif len(old_eps) >= 3:
+ # 4nd order Pseudo Linear Multistep (Adams-Bashforth)
+ e_t_prime = (55 * e_t - 59 * old_eps[-1] + 37 * old_eps[-2] - 9 * old_eps[-3]) / 24
+
+ x_prev, pred_x0 = get_x_prev_and_pred_x0(e_t_prime, index)
+
+ return x_prev, pred_x0, e_t
+
+# =================================================================================================
+# Monkey patch LatentInpaintDiffusion to load the checkpoint with a proper config.
+# Adapted from:
+# https://github.com/runwayml/stable-diffusion/blob/main/ldm/models/diffusion/ddpm.py
+# =================================================================================================
+
+@torch.no_grad()
+def get_unconditional_conditioning(self, batch_size, null_label=None):
+ if null_label is not None:
+ xc = null_label
+ if isinstance(xc, ListConfig):
+ xc = list(xc)
+ if isinstance(xc, dict) or isinstance(xc, list):
+ c = self.get_learned_conditioning(xc)
+ else:
+ if hasattr(xc, "to"):
+ xc = xc.to(self.device)
+ c = self.get_learned_conditioning(xc)
+ else:
+ # todo: get null label from cond_stage_model
+ raise NotImplementedError()
+ c = repeat(c, "1 ... -> b ...", b=batch_size).to(self.device)
+ return c
+
+
+class LatentInpaintDiffusion(LatentDiffusion):
+ def __init__(
+ self,
+ concat_keys=("mask", "masked_image"),
+ masked_image_key="masked_image",
+ *args,
+ **kwargs,
+ ):
+ super().__init__(*args, **kwargs)
+ self.masked_image_key = masked_image_key
+ assert self.masked_image_key in concat_keys
+ self.concat_keys = concat_keys
+
+
+def should_hijack_inpainting(checkpoint_info):
+ return str(checkpoint_info.filename).endswith("inpainting.ckpt") and not checkpoint_info.config.endswith("inpainting.yaml")
+
+
+def do_inpainting_hijack():
+ ldm.models.diffusion.ddpm.get_unconditional_conditioning = get_unconditional_conditioning
+ ldm.models.diffusion.ddpm.LatentInpaintDiffusion = LatentInpaintDiffusion
+
+ ldm.models.diffusion.ddim.DDIMSampler.p_sample_ddim = p_sample_ddim
+ ldm.models.diffusion.ddim.DDIMSampler.sample = sample_ddim
+
+ ldm.models.diffusion.plms.PLMSSampler.p_sample_plms = p_sample_plms
+ ldm.models.diffusion.plms.PLMSSampler.sample = sample_plms \ No newline at end of file
diff --git a/modules/sd_models.py b/modules/sd_models.py
index eae22e87..e697bb72 100644
--- a/modules/sd_models.py
+++ b/modules/sd_models.py
@@ -7,8 +7,9 @@ from omegaconf import OmegaConf
from ldm.util import instantiate_from_config
-from modules import shared, modelloader, devices
+from modules import shared, modelloader, devices, script_callbacks
from modules.paths import models_path
+from modules.sd_hijack_inpainting import do_inpainting_hijack, should_hijack_inpainting
model_dir = "Stable-diffusion"
model_path = os.path.abspath(os.path.join(models_path, model_dir))
@@ -20,7 +21,7 @@ checkpoints_loaded = collections.OrderedDict()
try:
# this silences the annoying "Some weights of the model checkpoint were not used when initializing..." message at start.
- from transformers import logging
+ from transformers import logging, CLIPModel
logging.set_verbosity_error()
except Exception:
@@ -154,6 +155,9 @@ def get_state_dict_from_checkpoint(pl_sd):
return pl_sd
+vae_ignore_keys = {"model_ema.decay", "model_ema.num_updates"}
+
+
def load_model_weights(model, checkpoint_info):
checkpoint_file = checkpoint_info.filename
sd_model_hash = checkpoint_info.hash
@@ -185,7 +189,7 @@ def load_model_weights(model, checkpoint_info):
if os.path.exists(vae_file):
print(f"Loading VAE weights from: {vae_file}")
vae_ckpt = torch.load(vae_file, map_location=shared.weight_load_location)
- vae_dict = {k: v for k, v in vae_ckpt["state_dict"].items() if k[0:4] != "loss"}
+ vae_dict = {k: v for k, v in vae_ckpt["state_dict"].items() if k[0:4] != "loss" and k not in vae_ignore_keys}
model.first_stage_model.load_state_dict(vae_dict)
model.first_stage_model.to(devices.dtype_vae)
@@ -203,14 +207,26 @@ def load_model_weights(model, checkpoint_info):
model.sd_checkpoint_info = checkpoint_info
-def load_model():
+def load_model(checkpoint_info=None):
from modules import lowvram, sd_hijack
- checkpoint_info = select_checkpoint()
+ checkpoint_info = checkpoint_info or select_checkpoint()
if checkpoint_info.config != shared.cmd_opts.config:
print(f"Loading config from: {checkpoint_info.config}")
sd_config = OmegaConf.load(checkpoint_info.config)
+
+ if should_hijack_inpainting(checkpoint_info):
+ # Hardcoded config for now...
+ sd_config.model.target = "ldm.models.diffusion.ddpm.LatentInpaintDiffusion"
+ sd_config.model.params.use_ema = False
+ sd_config.model.params.conditioning_key = "hybrid"
+ sd_config.model.params.unet_config.params.in_channels = 9
+
+ # Create a "fake" config with a different name so that we know to unload it when switching models.
+ checkpoint_info = checkpoint_info._replace(config=checkpoint_info.config.replace(".yaml", "-inpainting.yaml"))
+
+ do_inpainting_hijack()
sd_model = instantiate_from_config(sd_config.model)
load_model_weights(sd_model, checkpoint_info)
@@ -222,6 +238,9 @@ def load_model():
sd_hijack.model_hijack.hijack(sd_model)
sd_model.eval()
+ shared.sd_model = sd_model
+
+ script_callbacks.model_loaded_callback(sd_model)
print(f"Model loaded.")
return sd_model
@@ -234,9 +253,9 @@ def reload_model_weights(sd_model, info=None):
if sd_model.sd_model_checkpoint == checkpoint_info.filename:
return
- if sd_model.sd_checkpoint_info.config != checkpoint_info.config:
+ if sd_model.sd_checkpoint_info.config != checkpoint_info.config or should_hijack_inpainting(checkpoint_info) != should_hijack_inpainting(sd_model.sd_checkpoint_info):
checkpoints_loaded.clear()
- shared.sd_model = load_model()
+ load_model(checkpoint_info)
return shared.sd_model
if shared.cmd_opts.lowvram or shared.cmd_opts.medvram:
@@ -249,6 +268,7 @@ def reload_model_weights(sd_model, info=None):
load_model_weights(sd_model, checkpoint_info)
sd_hijack.model_hijack.hijack(sd_model)
+ script_callbacks.model_loaded_callback(sd_model)
if not shared.cmd_opts.lowvram and not shared.cmd_opts.medvram:
sd_model.to(devices.device)
diff --git a/modules/sd_samplers.py b/modules/sd_samplers.py
index b58e810b..3670b57d 100644
--- a/modules/sd_samplers.py
+++ b/modules/sd_samplers.py
@@ -7,7 +7,7 @@ import inspect
import k_diffusion.sampling
import ldm.models.diffusion.ddim
import ldm.models.diffusion.plms
-from modules import prompt_parser, devices, processing
+from modules import prompt_parser, devices, processing, images
from modules.shared import opts, cmd_opts, state
import modules.shared as shared
@@ -71,6 +71,7 @@ sampler_extra_params = {
'sample_dpm_2': ['s_churn', 's_tmin', 's_tmax', 's_noise'],
}
+
def setup_img2img_steps(p, steps=None):
if opts.img2img_fix_steps or steps is not None:
steps = int((steps or p.steps) / min(p.denoising_strength, 0.999)) if p.denoising_strength > 0 else 0
@@ -82,14 +83,22 @@ def setup_img2img_steps(p, steps=None):
return steps, t_enc
-def sample_to_image(samples):
- x_sample = processing.decode_first_stage(shared.sd_model, samples[0:1])[0]
+def single_sample_to_image(sample):
+ x_sample = processing.decode_first_stage(shared.sd_model, sample.unsqueeze(0))[0]
x_sample = torch.clamp((x_sample + 1.0) / 2.0, min=0.0, max=1.0)
x_sample = 255. * np.moveaxis(x_sample.cpu().numpy(), 0, 2)
x_sample = x_sample.astype(np.uint8)
return Image.fromarray(x_sample)
+def sample_to_image(samples):
+ return single_sample_to_image(samples[0])
+
+
+def samples_to_image_grid(samples):
+ return images.image_grid([single_sample_to_image(sample) for sample in samples])
+
+
def store_latent(decoded):
state.current_latent = decoded
@@ -117,6 +126,8 @@ class VanillaStableDiffusionSampler:
self.config = None
self.last_latent = None
+ self.conditioning_key = sd_model.model.conditioning_key
+
def number_of_needed_noises(self, p):
return 0
@@ -136,6 +147,12 @@ class VanillaStableDiffusionSampler:
if self.stop_at is not None and self.step > self.stop_at:
raise InterruptedException
+ # Have to unwrap the inpainting conditioning here to perform pre-processing
+ image_conditioning = None
+ if isinstance(cond, dict):
+ image_conditioning = cond["c_concat"][0]
+ cond = cond["c_crossattn"][0]
+ unconditional_conditioning = unconditional_conditioning["c_crossattn"][0]
conds_list, tensor = prompt_parser.reconstruct_multicond_batch(cond, self.step)
unconditional_conditioning = prompt_parser.reconstruct_cond_batch(unconditional_conditioning, self.step)
@@ -157,6 +174,12 @@ class VanillaStableDiffusionSampler:
img_orig = self.sampler.model.q_sample(self.init_latent, ts)
x_dec = img_orig * self.mask + self.nmask * x_dec
+ # Wrap the image conditioning back up since the DDIM code can accept the dict directly.
+ # Note that they need to be lists because it just concatenates them later.
+ if image_conditioning is not None:
+ cond = {"c_concat": [image_conditioning], "c_crossattn": [cond]}
+ unconditional_conditioning = {"c_concat": [image_conditioning], "c_crossattn": [unconditional_conditioning]}
+
res = self.orig_p_sample_ddim(x_dec, cond, ts, unconditional_conditioning=unconditional_conditioning, *args, **kwargs)
if self.mask is not None:
@@ -182,7 +205,7 @@ class VanillaStableDiffusionSampler:
self.mask = p.mask if hasattr(p, 'mask') else None
self.nmask = p.nmask if hasattr(p, 'nmask') else None
- def sample_img2img(self, p, x, noise, conditioning, unconditional_conditioning, steps=None):
+ def sample_img2img(self, p, x, noise, conditioning, unconditional_conditioning, steps=None, image_conditioning=None):
steps, t_enc = setup_img2img_steps(p, steps)
self.initialize(p)
@@ -196,20 +219,33 @@ class VanillaStableDiffusionSampler:
x1 = self.sampler.stochastic_encode(x, torch.tensor([t_enc] * int(x.shape[0])).to(shared.device), noise=noise)
self.init_latent = x
+ self.last_latent = x
self.step = 0
- samples = self.launch_sampling(steps, lambda: self.sampler.decode(x1, conditioning, t_enc, unconditional_guidance_scale=p.cfg_scale, unconditional_conditioning=unconditional_conditioning))
+ # Wrap the conditioning models with additional image conditioning for inpainting model
+ if image_conditioning is not None:
+ conditioning = {"c_concat": [image_conditioning], "c_crossattn": [conditioning]}
+ unconditional_conditioning = {"c_concat": [image_conditioning], "c_crossattn": [unconditional_conditioning]}
+
+
+ samples = self.launch_sampling(t_enc + 1, lambda: self.sampler.decode(x1, conditioning, t_enc, unconditional_guidance_scale=p.cfg_scale, unconditional_conditioning=unconditional_conditioning))
return samples
- def sample(self, p, x, conditioning, unconditional_conditioning, steps=None):
+ def sample(self, p, x, conditioning, unconditional_conditioning, steps=None, image_conditioning=None):
self.initialize(p)
self.init_latent = None
+ self.last_latent = x
self.step = 0
steps = steps or p.steps
+ # Wrap the conditioning models with additional image conditioning for inpainting model
+ if image_conditioning is not None:
+ conditioning = {"c_concat": [image_conditioning], "c_crossattn": [conditioning]}
+ unconditional_conditioning = {"c_concat": [image_conditioning], "c_crossattn": [unconditional_conditioning]}
+
# existing code fails with certain step counts, like 9
try:
samples_ddim = self.launch_sampling(steps, lambda: self.sampler.sample(S=steps, conditioning=conditioning, batch_size=int(x.shape[0]), shape=x[0].shape, verbose=False, unconditional_guidance_scale=p.cfg_scale, unconditional_conditioning=unconditional_conditioning, x_T=x, eta=self.eta)[0])
@@ -228,7 +264,7 @@ class CFGDenoiser(torch.nn.Module):
self.init_latent = None
self.step = 0
- def forward(self, x, sigma, uncond, cond, cond_scale):
+ def forward(self, x, sigma, uncond, cond, cond_scale, image_cond):
if state.interrupted or state.skipped:
raise InterruptedException
@@ -239,28 +275,29 @@ class CFGDenoiser(torch.nn.Module):
repeats = [len(conds_list[i]) for i in range(batch_size)]
x_in = torch.cat([torch.stack([x[i] for _ in range(n)]) for i, n in enumerate(repeats)] + [x])
+ image_cond_in = torch.cat([torch.stack([image_cond[i] for _ in range(n)]) for i, n in enumerate(repeats)] + [image_cond])
sigma_in = torch.cat([torch.stack([sigma[i] for _ in range(n)]) for i, n in enumerate(repeats)] + [sigma])
if tensor.shape[1] == uncond.shape[1]:
cond_in = torch.cat([tensor, uncond])
if shared.batch_cond_uncond:
- x_out = self.inner_model(x_in, sigma_in, cond=cond_in)
+ x_out = self.inner_model(x_in, sigma_in, cond={"c_crossattn": [cond_in], "c_concat": [image_cond_in]})
else:
x_out = torch.zeros_like(x_in)
for batch_offset in range(0, x_out.shape[0], batch_size):
a = batch_offset
b = a + batch_size
- x_out[a:b] = self.inner_model(x_in[a:b], sigma_in[a:b], cond=cond_in[a:b])
+ x_out[a:b] = self.inner_model(x_in[a:b], sigma_in[a:b], cond={"c_crossattn": [cond_in[a:b]], "c_concat": [image_cond_in[a:b]]})
else:
x_out = torch.zeros_like(x_in)
batch_size = batch_size*2 if shared.batch_cond_uncond else batch_size
for batch_offset in range(0, tensor.shape[0], batch_size):
a = batch_offset
b = min(a + batch_size, tensor.shape[0])
- x_out[a:b] = self.inner_model(x_in[a:b], sigma_in[a:b], cond=tensor[a:b])
+ x_out[a:b] = self.inner_model(x_in[a:b], sigma_in[a:b], cond={"c_crossattn": [tensor[a:b]], "c_concat": [image_cond_in[a:b]]})
- x_out[-uncond.shape[0]:] = self.inner_model(x_in[-uncond.shape[0]:], sigma_in[-uncond.shape[0]:], cond=uncond)
+ x_out[-uncond.shape[0]:] = self.inner_model(x_in[-uncond.shape[0]:], sigma_in[-uncond.shape[0]:], cond={"c_crossattn": [uncond], "c_concat": [image_cond_in[-uncond.shape[0]:]]})
denoised_uncond = x_out[-uncond.shape[0]:]
denoised = torch.clone(denoised_uncond)
@@ -306,6 +343,8 @@ class KDiffusionSampler:
self.config = None
self.last_latent = None
+ self.conditioning_key = sd_model.model.conditioning_key
+
def callback_state(self, d):
step = d['i']
latent = d["denoised"]
@@ -361,7 +400,7 @@ class KDiffusionSampler:
return extra_params_kwargs
- def sample_img2img(self, p, x, noise, conditioning, unconditional_conditioning, steps=None):
+ def sample_img2img(self, p, x, noise, conditioning, unconditional_conditioning, steps=None, image_conditioning=None):
steps, t_enc = setup_img2img_steps(p, steps)
if p.sampler_noise_scheduler_override:
@@ -388,12 +427,18 @@ class KDiffusionSampler:
extra_params_kwargs['sigmas'] = sigma_sched
self.model_wrap_cfg.init_latent = x
+ self.last_latent = x
- samples = self.launch_sampling(steps, lambda: self.func(self.model_wrap_cfg, xi, extra_args={'cond': conditioning, 'uncond': unconditional_conditioning, 'cond_scale': p.cfg_scale}, disable=False, callback=self.callback_state, **extra_params_kwargs))
+ samples = self.launch_sampling(t_enc + 1, lambda: self.func(self.model_wrap_cfg, xi, extra_args={
+ 'cond': conditioning,
+ 'image_cond': image_conditioning,
+ 'uncond': unconditional_conditioning,
+ 'cond_scale': p.cfg_scale
+ }, disable=False, callback=self.callback_state, **extra_params_kwargs))
return samples
- def sample(self, p, x, conditioning, unconditional_conditioning, steps=None):
+ def sample(self, p, x, conditioning, unconditional_conditioning, steps=None, image_conditioning = None):
steps = steps or p.steps
if p.sampler_noise_scheduler_override:
@@ -414,7 +459,13 @@ class KDiffusionSampler:
else:
extra_params_kwargs['sigmas'] = sigmas
- samples = self.launch_sampling(steps, lambda: self.func(self.model_wrap_cfg, x, extra_args={'cond': conditioning, 'uncond': unconditional_conditioning, 'cond_scale': p.cfg_scale}, disable=False, callback=self.callback_state, **extra_params_kwargs))
+ self.last_latent = x
+ samples = self.launch_sampling(steps, lambda: self.func(self.model_wrap_cfg, x, extra_args={
+ 'cond': conditioning,
+ 'image_cond': image_conditioning,
+ 'uncond': unconditional_conditioning,
+ 'cond_scale': p.cfg_scale
+ }, disable=False, callback=self.callback_state, **extra_params_kwargs))
return samples
diff --git a/modules/shared.py b/modules/shared.py
index f7d66870..308fccce 100644
--- a/modules/shared.py
+++ b/modules/shared.py
@@ -3,6 +3,7 @@ import datetime
import json
import os
import sys
+from collections import OrderedDict
import gradio as gr
import tqdm
@@ -57,12 +58,13 @@ parser.add_argument("--opt-split-attention", action='store_true', help="force-en
parser.add_argument("--opt-split-attention-invokeai", action='store_true', help="force-enables InvokeAI's cross-attention layer optimization. By default, it's on when cuda is unavailable.")
parser.add_argument("--opt-split-attention-v1", action='store_true', help="enable older version of split attention optimization that does not consume all the VRAM it can find")
parser.add_argument("--disable-opt-split-attention", action='store_true', help="force-disables cross-attention layer optimization")
-parser.add_argument("--use-cpu", nargs='+',choices=['all', 'sd', 'interrogate', 'gfpgan', 'bsrgan', 'esrgan', 'scunet', 'codeformer'], help="use CPU as torch device for specified modules", default=[], type=str.lower)
+parser.add_argument("--use-cpu", nargs='+',choices=['all', 'sd', 'interrogate', 'gfpgan', 'swinir', 'esrgan', 'scunet', 'codeformer'], help="use CPU as torch device for specified modules", default=[], type=str.lower)
parser.add_argument("--listen", action='store_true', help="launch gradio with 0.0.0.0 as server name, allowing to respond to network requests")
parser.add_argument("--port", type=int, help="launch gradio with given server port, you need root/admin rights for ports < 1024, defaults to 7860 if available", default=None)
parser.add_argument("--show-negative-prompt", action='store_true', help="does not do anything", default=False)
parser.add_argument("--ui-config-file", type=str, help="filename to use for ui configuration", default=os.path.join(script_path, 'ui-config.json'))
parser.add_argument("--hide-ui-dir-config", action='store_true', help="hide directory configuration from webui", default=False)
+parser.add_argument("--freeze-settings", action='store_true', help="disable editing settings", default=False)
parser.add_argument("--ui-settings-file", type=str, help="filename to use for ui settings", default=os.path.join(script_path, 'config.json'))
parser.add_argument("--gradio-debug", action='store_true', help="launch gradio with --debug option")
parser.add_argument("--gradio-auth", type=str, help='set gradio authentication like "username:password"; or comma-delimit multiple like "u1:p1,u2:p2,u3:p3"', default=None)
@@ -78,10 +80,13 @@ parser.add_argument('--vae-path', type=str, help='Path to Variational Autoencode
parser.add_argument("--disable-safe-unpickle", action='store_true', help="disable checking pytorch models for malicious code", default=False)
parser.add_argument("--api", action='store_true', help="use api=True to launch the api with the webui")
parser.add_argument("--nowebui", action='store_true', help="use api=True to launch the api instead of the webui")
+parser.add_argument("--ui-debug-mode", action='store_true', help="Don't load model to quickly launch UI")
+parser.add_argument("--device-id", type=str, help="Select the default CUDA device to use (export CUDA_VISIBLE_DEVICES=0,1,etc might be needed before)", default=None)
cmd_opts = parser.parse_args()
restricted_opts = [
"samples_filename_pattern",
+ "directories_filename_pattern",
"outdir_samples",
"outdir_txt2img_samples",
"outdir_img2img_samples",
@@ -91,8 +96,8 @@ restricted_opts = [
"outdir_save",
]
-devices.device, devices.device_interrogate, devices.device_gfpgan, devices.device_bsrgan, devices.device_esrgan, devices.device_scunet, devices.device_codeformer = \
-(devices.cpu if any(y in cmd_opts.use_cpu for y in [x, 'all']) else devices.get_optimal_device() for x in ['sd', 'interrogate', 'gfpgan', 'bsrgan', 'esrgan', 'scunet', 'codeformer'])
+devices.device, devices.device_interrogate, devices.device_gfpgan, devices.device_swinir, devices.device_esrgan, devices.device_scunet, devices.device_codeformer = \
+(devices.cpu if any(y in cmd_opts.use_cpu for y in [x, 'all']) else devices.get_optimal_device() for x in ['sd', 'interrogate', 'gfpgan', 'swinir', 'esrgan', 'scunet', 'codeformer'])
device = devices.device
weight_load_location = None if cmd_opts.lowram else "cpu"
@@ -137,7 +142,7 @@ class State:
self.job_no += 1
self.sampling_step = 0
self.current_image_sampling_step = 0
-
+
def get_job_timestamp(self):
return datetime.datetime.now().strftime("%Y%m%d%H%M%S") # shouldn't this return job_timestamp?
@@ -162,13 +167,13 @@ def realesrgan_models_names():
class OptionInfo:
- def __init__(self, default=None, label="", component=None, component_args=None, onchange=None, show_on_main_page=False, refresh=None):
+ def __init__(self, default=None, label="", component=None, component_args=None, onchange=None, section=None, refresh=None):
self.default = default
self.label = label
self.component = component
self.component_args = component_args
self.onchange = onchange
- self.section = None
+ self.section = section
self.refresh = refresh
@@ -186,7 +191,8 @@ options_templates = {}
options_templates.update(options_section(('saving-images', "Saving images/grids"), {
"samples_save": OptionInfo(True, "Always save all generated images"),
"samples_format": OptionInfo('png', 'File format for images'),
- "samples_filename_pattern": OptionInfo("", "Images filename pattern"),
+ "samples_filename_pattern": OptionInfo("", "Images filename pattern", component_args=hide_dirs),
+ "save_images_add_number": OptionInfo(True, "Add number to filename when saving", component_args=hide_dirs),
"grid_save": OptionInfo(True, "Always save all generated image grids"),
"grid_format": OptionInfo('png', 'File format for grids'),
@@ -221,8 +227,8 @@ options_templates.update(options_section(('saving-to-dirs', "Saving to a directo
"save_to_dirs": OptionInfo(False, "Save images to a subdirectory"),
"grid_save_to_dirs": OptionInfo(False, "Save grids to a subdirectory"),
"use_save_to_dirs_for_ui": OptionInfo(False, "When using \"Save\" button, save images to a subdirectory"),
- "directories_filename_pattern": OptionInfo("", "Directory name pattern"),
- "directories_max_prompt_words": OptionInfo(8, "Max prompt words for [prompt_words] pattern", gr.Slider, {"minimum": 1, "maximum": 20, "step": 1}),
+ "directories_filename_pattern": OptionInfo("", "Directory name pattern", component_args=hide_dirs),
+ "directories_max_prompt_words": OptionInfo(8, "Max prompt words for [prompt_words] pattern", gr.Slider, {"minimum": 1, "maximum": 20, "step": 1, **hide_dirs}),
}))
options_templates.update(options_section(('upscaling', "Upscaling"), {
@@ -249,7 +255,7 @@ options_templates.update(options_section(('system', "System"), {
}))
options_templates.update(options_section(('training', "Training"), {
- "unload_models_when_training": OptionInfo(False, "Unload VAE and CLIP from VRAM when training"),
+ "unload_models_when_training": OptionInfo(False, "Move VAE and CLIP to RAM when training hypernetwork. Saves VRAM."),
"dataset_filename_word_regex": OptionInfo("", "Filename word regex"),
"dataset_filename_join_string": OptionInfo(" ", "Filename join string"),
"training_image_repeats_per_epoch": OptionInfo(1, "Number of repeats for a single input image per epoch; used only for displaying epoch number", gr.Number, {"precision": 0}),
@@ -291,6 +297,7 @@ options_templates.update(options_section(('interrogate', "Interrogate Options"),
options_templates.update(options_section(('ui', "User interface"), {
"show_progressbar": OptionInfo(True, "Show progressbar"),
"show_progress_every_n_steps": OptionInfo(0, "Show image creation progress every N sampling steps. Set 0 to disable.", gr.Slider, {"minimum": 0, "maximum": 32, "step": 1}),
+ "show_progress_grid": OptionInfo(True, "Show previews of all images generated in a batch as a grid"),
"return_grid": OptionInfo(True, "Show grid in results for web"),
"do_not_show_images": OptionInfo(False, "Do not show any images in results for web"),
"add_model_hash_to_info": OptionInfo(True, "Add model hash to generation information"),
@@ -343,7 +350,7 @@ class Options:
def save(self, filename):
with open(filename, "w", encoding="utf8") as file:
- json.dump(self.data, file)
+ json.dump(self.data, file, indent=4)
def same_type(self, x, y):
if x is None or y is None:
@@ -378,6 +385,20 @@ class Options:
d = {k: self.data.get(k, self.data_labels.get(k).default) for k in self.data_labels.keys()}
return json.dumps(d)
+ def add_option(self, key, info):
+ self.data_labels[key] = info
+
+ def reorder(self):
+ """reorder settings so that all items related to section always go together"""
+
+ section_ids = {}
+ settings_items = self.data_labels.items()
+ for k, item in settings_items:
+ if item.section not in section_ids:
+ section_ids[item.section] = len(section_ids)
+
+ self.data_labels = {k: v for k, v in sorted(settings_items, key=lambda x: section_ids[x[1].section])}
+
opts = Options()
if os.path.exists(config_filename):
@@ -387,6 +408,8 @@ sd_upscalers = []
sd_model = None
+clip_model = None
+
progress_print_out = sys.stdout
diff --git a/modules/swinir_model.py b/modules/swinir_model.py
index baa02e3d..4253b66d 100644
--- a/modules/swinir_model.py
+++ b/modules/swinir_model.py
@@ -7,8 +7,8 @@ from PIL import Image
from basicsr.utils.download_util import load_file_from_url
from tqdm import tqdm
-from modules import modelloader
-from modules.shared import cmd_opts, opts, device
+from modules import modelloader, devices
+from modules.shared import cmd_opts, opts
from modules.swinir_model_arch import SwinIR as net
from modules.swinir_model_arch_v2 import Swin2SR as net2
from modules.upscaler import Upscaler, UpscalerData
@@ -42,7 +42,7 @@ class UpscalerSwinIR(Upscaler):
model = self.load_model(model_file)
if model is None:
return img
- model = model.to(device)
+ model = model.to(devices.device_swinir)
img = upscale(img, model)
try:
torch.cuda.empty_cache()
@@ -111,7 +111,7 @@ def upscale(
img = img[:, :, ::-1]
img = np.moveaxis(img, 2, 0) / 255
img = torch.from_numpy(img).float()
- img = img.unsqueeze(0).to(device)
+ img = devices.mps_contiguous_to(img.unsqueeze(0), devices.device_swinir)
with torch.no_grad(), precision_scope("cuda"):
_, _, h_old, w_old = img.size()
h_pad = (h_old // window_size + 1) * window_size - h_old
@@ -139,8 +139,8 @@ def inference(img, model, tile, tile_overlap, window_size, scale):
stride = tile - tile_overlap
h_idx_list = list(range(0, h - tile, stride)) + [h - tile]
w_idx_list = list(range(0, w - tile, stride)) + [w - tile]
- E = torch.zeros(b, c, h * sf, w * sf, dtype=torch.half, device=device).type_as(img)
- W = torch.zeros_like(E, dtype=torch.half, device=device)
+ E = torch.zeros(b, c, h * sf, w * sf, dtype=torch.half, device=devices.device_swinir).type_as(img)
+ W = torch.zeros_like(E, dtype=torch.half, device=devices.device_swinir)
with tqdm(total=len(h_idx_list) * len(w_idx_list), desc="SwinIR tiles") as pbar:
for h_idx in h_idx_list:
diff --git a/modules/textual_inversion/dataset.py b/modules/textual_inversion/dataset.py
index 23bb4b6a..5b1c5002 100644
--- a/modules/textual_inversion/dataset.py
+++ b/modules/textual_inversion/dataset.py
@@ -83,7 +83,7 @@ class PersonalizedBase(Dataset):
self.dataset.append(entry)
- assert len(self.dataset) > 1, "No images have been found in the dataset."
+ assert len(self.dataset) > 0, "No images have been found in the dataset."
self.length = len(self.dataset) * repeats // batch_size
self.initial_indexes = np.arange(len(self.dataset))
@@ -91,7 +91,7 @@ class PersonalizedBase(Dataset):
self.shuffle()
def shuffle(self):
- self.indexes = self.initial_indexes[torch.randperm(self.initial_indexes.shape[0])]
+ self.indexes = self.initial_indexes[torch.randperm(self.initial_indexes.shape[0]).numpy()]
def create_text(self, filename_text):
text = random.choice(self.lines)
diff --git a/modules/textual_inversion/image_embedding.py b/modules/textual_inversion/image_embedding.py
index 898ce3b3..ea653806 100644
--- a/modules/textual_inversion/image_embedding.py
+++ b/modules/textual_inversion/image_embedding.py
@@ -5,6 +5,7 @@ import zlib
from PIL import Image, PngImagePlugin, ImageDraw, ImageFont
from fonts.ttf import Roboto
import torch
+from modules.shared import opts
class EmbeddingEncoder(json.JSONEncoder):
@@ -133,7 +134,7 @@ def caption_image_overlay(srcimage, title, footerLeft, footerMid, footerRight, t
from math import cos
image = srcimage.copy()
-
+ fontsize = 32
if textfont is None:
try:
textfont = ImageFont.truetype(opts.font or Roboto, fontsize)
@@ -150,7 +151,7 @@ def caption_image_overlay(srcimage, title, footerLeft, footerMid, footerRight, t
image = Image.alpha_composite(image.convert('RGBA'), gradient.resize(image.size))
draw = ImageDraw.Draw(image)
- fontsize = 32
+
font = ImageFont.truetype(textfont, fontsize)
padding = 10
diff --git a/modules/textual_inversion/preprocess.py b/modules/textual_inversion/preprocess.py
index 0c79f012..a8c17c6f 100644
--- a/modules/textual_inversion/preprocess.py
+++ b/modules/textual_inversion/preprocess.py
@@ -1,5 +1,6 @@
import os
from PIL import Image, ImageOps
+import math
import platform
import sys
import tqdm
@@ -12,7 +13,7 @@ if cmd_opts.deepdanbooru:
import modules.deepbooru as deepbooru
-def preprocess(process_src, process_dst, process_width, process_height, process_flip, process_split, process_caption, process_caption_deepbooru=False, process_entropy_focus=False):
+def preprocess(process_src, process_dst, process_width, process_height, preprocess_txt_action, process_flip, process_split, process_caption, process_caption_deepbooru=False, split_threshold=0.5, overlap_ratio=0.2, process_entropy_focus=False):
try:
if process_caption:
shared.interrogator.load()
@@ -22,7 +23,7 @@ def preprocess(process_src, process_dst, process_width, process_height, process_
db_opts[deepbooru.OPT_INCLUDE_RANKS] = False
deepbooru.create_deepbooru_process(opts.interrogate_deepbooru_score_threshold, db_opts)
- preprocess_work(process_src, process_dst, process_width, process_height, process_flip, process_split, process_caption, process_caption_deepbooru, process_entropy_focus)
+ preprocess_work(process_src, process_dst, process_width, process_height, preprocess_txt_action, process_flip, process_split, process_caption, process_caption_deepbooru, split_threshold, overlap_ratio, process_entropy_focus)
finally:
@@ -34,11 +35,13 @@ def preprocess(process_src, process_dst, process_width, process_height, process_
-def preprocess_work(process_src, process_dst, process_width, process_height, process_flip, process_split, process_caption, process_caption_deepbooru=False, process_entropy_focus=False):
+def preprocess_work(process_src, process_dst, process_width, process_height, preprocess_txt_action, process_flip, process_split, process_caption, process_caption_deepbooru=False, split_threshold=0.5, overlap_ratio=0.2, process_entropy_focus=False):
width = process_width
height = process_height
src = os.path.abspath(process_src)
dst = os.path.abspath(process_dst)
+ split_threshold = max(0.0, min(1.0, split_threshold))
+ overlap_ratio = max(0.0, min(0.9, overlap_ratio))
assert src != dst, 'same directory specified as source and destination'
@@ -49,7 +52,7 @@ def preprocess_work(process_src, process_dst, process_width, process_height, pro
shared.state.textinfo = "Preprocessing..."
shared.state.job_count = len(files)
- def save_pic_with_caption(image, index):
+ def save_pic_with_caption(image, index, existing_caption=None):
caption = ""
if process_caption:
@@ -67,17 +70,49 @@ def preprocess_work(process_src, process_dst, process_width, process_height, pro
basename = f"{index:05}-{subindex[0]}-{filename_part}"
image.save(os.path.join(dst, f"{basename}.png"))
+ if preprocess_txt_action == 'prepend' and existing_caption:
+ caption = existing_caption + ' ' + caption
+ elif preprocess_txt_action == 'append' and existing_caption:
+ caption = caption + ' ' + existing_caption
+ elif preprocess_txt_action == 'copy' and existing_caption:
+ caption = existing_caption
+
+ caption = caption.strip()
+
if len(caption) > 0:
with open(os.path.join(dst, f"{basename}.txt"), "w", encoding="utf8") as file:
file.write(caption)
subindex[0] += 1
- def save_pic(image, index):
- save_pic_with_caption(image, index)
+ def save_pic(image, index, existing_caption=None):
+ save_pic_with_caption(image, index, existing_caption=existing_caption)
if process_flip:
- save_pic_with_caption(ImageOps.mirror(image), index)
+ save_pic_with_caption(ImageOps.mirror(image), index, existing_caption=existing_caption)
+
+ def split_pic(image, inverse_xy):
+ if inverse_xy:
+ from_w, from_h = image.height, image.width
+ to_w, to_h = height, width
+ else:
+ from_w, from_h = image.width, image.height
+ to_w, to_h = width, height
+ h = from_h * to_w // from_w
+ if inverse_xy:
+ image = image.resize((h, to_w))
+ else:
+ image = image.resize((to_w, h))
+
+ split_count = math.ceil((h - to_h * overlap_ratio) / (to_h * (1.0 - overlap_ratio)))
+ y_step = (h - to_h) / (split_count - 1)
+ for i in range(split_count):
+ y = int(y_step * i)
+ if inverse_xy:
+ splitted = image.crop((y, 0, y + to_h, to_w))
+ else:
+ splitted = image.crop((0, y, to_w, y + to_h))
+ yield splitted
for index, imagefile in enumerate(tqdm.tqdm(files)):
@@ -88,34 +123,27 @@ def preprocess_work(process_src, process_dst, process_width, process_height, pro
except Exception:
continue
+ existing_caption = None
+ existing_caption_filename = os.path.splitext(filename)[0] + '.txt'
+ if os.path.exists(existing_caption_filename):
+ with open(existing_caption_filename, 'r', encoding="utf8") as file:
+ existing_caption = file.read()
+
if shared.state.interrupted:
break
- ratio = img.height / img.width
- is_tall = ratio > 1.35
- is_wide = ratio < 1 / 1.35
+ if img.height > img.width:
+ ratio = (img.width * height) / (img.height * width)
+ inverse_xy = False
+ else:
+ ratio = (img.height * width) / (img.width * height)
+ inverse_xy = True
processing_option_ran = False
- if process_split and is_tall:
- img = img.resize((width, height * img.height // img.width))
-
- top = img.crop((0, 0, width, height))
- save_pic(top, index)
-
- bot = img.crop((0, img.height - height, width, img.height))
- save_pic(bot, index)
-
- processing_option_ran = True
- elif process_split and is_wide:
- img = img.resize((width * img.width // img.height, height))
-
- left = img.crop((0, 0, width, height))
- save_pic(left, index)
-
- right = img.crop((img.width - width, 0, img.width, height))
- save_pic(right, index)
-
+ if process_split and ratio < 1.0 and ratio <= split_threshold:
+ for splitted in split_pic(img, inverse_xy):
+ save_pic(splitted, index, existing_caption=existing_caption)
processing_option_ran = True
if process_entropy_focus and img.height != img.width:
@@ -128,12 +156,11 @@ def preprocess_work(process_src, process_dst, process_width, process_height, pro
annotate_image = False
)
focal = autocrop.crop_image(img, autocrop_settings)
- save_pic(focal, index)
-
+ save_pic(focal, index, existing_caption=existing_caption)
processing_option_ran = True
if not processing_option_ran:
img = images.resize_image(1, img, width, height)
- save_pic(img, index)
+ save_pic(img, index, existing_caption=existing_caption)
shared.state.nextjob() \ No newline at end of file
diff --git a/modules/textual_inversion/textual_inversion.py b/modules/textual_inversion/textual_inversion.py
index 3be69562..529ed3e2 100644
--- a/modules/textual_inversion/textual_inversion.py
+++ b/modules/textual_inversion/textual_inversion.py
@@ -153,7 +153,7 @@ class EmbeddingDatabase:
return None, None
-def create_embedding(name, num_vectors_per_token, init_text='*'):
+def create_embedding(name, num_vectors_per_token, overwrite_old, init_text='*'):
cond_model = shared.sd_model.cond_stage_model
embedding_layer = cond_model.wrapped.transformer.text_model.embeddings
@@ -165,7 +165,8 @@ def create_embedding(name, num_vectors_per_token, init_text='*'):
vec[i] = embedded[i * int(embedded.shape[0]) // num_vectors_per_token]
fn = os.path.join(shared.cmd_opts.embeddings_dir, f"{name}.pt")
- assert not os.path.exists(fn), f"file {fn} already exists"
+ if not overwrite_old:
+ assert not os.path.exists(fn), f"file {fn} already exists"
embedding = Embedding(vec, name)
embedding.step = 0
@@ -275,6 +276,7 @@ def train_embedding(embedding_name, learn_rate, batch_size, data_root, log_direc
loss.backward()
optimizer.step()
+
epoch_num = embedding.step // len(ds)
epoch_step = embedding.step - (epoch_num * len(ds)) + 1
diff --git a/modules/textual_inversion/ui.py b/modules/textual_inversion/ui.py
index 36881e7a..e712284d 100644
--- a/modules/textual_inversion/ui.py
+++ b/modules/textual_inversion/ui.py
@@ -7,8 +7,8 @@ import modules.textual_inversion.preprocess
from modules import sd_hijack, shared
-def create_embedding(name, initialization_text, nvpt):
- filename = modules.textual_inversion.textual_inversion.create_embedding(name, nvpt, init_text=initialization_text)
+def create_embedding(name, initialization_text, nvpt, overwrite_old):
+ filename = modules.textual_inversion.textual_inversion.create_embedding(name, nvpt, overwrite_old, init_text=initialization_text)
sd_hijack.model_hijack.embedding_db.load_textual_inversion_embeddings()
diff --git a/modules/txt2img.py b/modules/txt2img.py
index 2381347f..c9d5a090 100644
--- a/modules/txt2img.py
+++ b/modules/txt2img.py
@@ -1,5 +1,6 @@
import modules.scripts
-from modules.processing import StableDiffusionProcessing, Processed, StableDiffusionProcessingTxt2Img, StableDiffusionProcessingImg2Img, process_images
+from modules.processing import StableDiffusionProcessing, Processed, StableDiffusionProcessingTxt2Img, \
+ StableDiffusionProcessingImg2Img, process_images
from modules.shared import opts, cmd_opts
import modules.shared as shared
import modules.processing as processing
@@ -35,6 +36,9 @@ def txt2img(prompt: str, negative_prompt: str, prompt_style: str, prompt_style2:
firstphase_height=firstphase_height if enable_hr else None,
)
+ p.scripts = modules.scripts.scripts_txt2img
+ p.script_args = args
+
if cmd_opts.enable_console_prompts:
print(f"\ntxt2img: {prompt}", file=shared.progress_print_out)
@@ -53,4 +57,3 @@ def txt2img(prompt: str, negative_prompt: str, prompt_style: str, prompt_style2:
processed.images = []
return processed.images, generation_info_js, plaintext_to_html(processed.info)
-
diff --git a/modules/ui.py b/modules/ui.py
index b6be713b..028eb4e5 100644
--- a/modules/ui.py
+++ b/modules/ui.py
@@ -5,47 +5,56 @@ import json
import math
import mimetypes
import os
+import platform
import random
+import subprocess as sp
import sys
import tempfile
import time
import traceback
-import platform
-import subprocess as sp
from functools import partial, reduce
+import gradio as gr
+import gradio.routes
+import gradio.utils
import numpy as np
+import piexif
import torch
from PIL import Image, PngImagePlugin
-import piexif
import gradio as gr
import gradio.utils
import gradio.routes
-from modules import sd_hijack, sd_models, localization
+from modules import sd_hijack, sd_models, localization, script_callbacks
from modules.paths import script_path
+
from modules.shared import opts, cmd_opts, restricted_opts
+
if cmd_opts.deepdanbooru:
from modules.deepbooru import get_deepbooru_tags
-import modules.shared as shared
-from modules.sd_samplers import samplers, samplers_for_img2img
-from modules.sd_hijack import model_hijack
+
+import modules.codeformer_model
+import modules.generation_parameters_copypaste
+import modules.gfpgan_model
+import modules.hypernetworks.ui
import modules.ldsr_model
import modules.scripts
-import modules.gfpgan_model
-import modules.codeformer_model
+import modules.shared as shared
import modules.styles
-import modules.generation_parameters_copypaste
+import modules.textual_inversion.ui
from modules import prompt_parser
from modules.images import save_image
+from modules.sd_hijack import model_hijack
+from modules.sd_samplers import samplers, samplers_for_img2img
import modules.textual_inversion.ui
import modules.hypernetworks.ui
-import modules.images_history as img_his
# this is a fix for Windows users. Without it, javascript files will be served with text/html content-type and the browser will not show any UI
mimetypes.init()
mimetypes.add_type('application/javascript', '.js')
+txt2img_paste_fields = []
+img2img_paste_fields = []
if not cmd_opts.share and not cmd_opts.listen:
@@ -268,8 +277,13 @@ def calc_time_left(progress, threshold, label, force_display):
time_since_start = time.time() - shared.state.time_start
eta = (time_since_start/progress)
eta_relative = eta-time_since_start
- if (eta_relative > threshold and progress > 0.02) or force_display:
- return label + time.strftime('%H:%M:%S', time.gmtime(eta_relative))
+ if (eta_relative > threshold and progress > 0.02) or force_display:
+ if eta_relative > 3600:
+ return label + time.strftime('%H:%M:%S', time.gmtime(eta_relative))
+ elif eta_relative > 60:
+ return label + time.strftime('%M:%S', time.gmtime(eta_relative))
+ else:
+ return label + time.strftime('%Ss', time.gmtime(eta_relative))
else:
return ""
@@ -285,7 +299,7 @@ def check_progress_call(id_part):
if shared.state.sampling_steps > 0:
progress += 1 / shared.state.job_count * shared.state.sampling_step / shared.state.sampling_steps
- time_left = calc_time_left( progress, 60, " ETA:", shared.state.time_left_force_display )
+ time_left = calc_time_left( progress, 1, " ETA: ", shared.state.time_left_force_display )
if time_left != "":
shared.state.time_left_force_display = True
@@ -293,7 +307,7 @@ def check_progress_call(id_part):
progressbar = ""
if opts.show_progressbar:
- progressbar = f"""<div class='progressDiv'><div class='progress' style="overflow:hidden;width:{progress * 100}%">{str(int(progress*100))+"%"+time_left if progress > 0.01 else ""}</div></div>"""
+ progressbar = f"""<div class='progressDiv'><div class='progress' style="overflow:visible;width:{progress * 100}%;white-space:nowrap;">{"&nbsp;" * 2 + str(int(progress*100))+"%" + time_left if progress > 0.01 else ""}</div></div>"""
image = gr_show(False)
preview_visibility = gr_show(False)
@@ -302,7 +316,10 @@ def check_progress_call(id_part):
if shared.parallel_processing_allowed:
if shared.state.sampling_step - shared.state.current_image_sampling_step >= opts.show_progress_every_n_steps and shared.state.current_latent is not None:
- shared.state.current_image = modules.sd_samplers.sample_to_image(shared.state.current_latent)
+ if opts.show_progress_grid:
+ shared.state.current_image = modules.sd_samplers.samples_to_image_grid(shared.state.current_latent)
+ else:
+ shared.state.current_image = modules.sd_samplers.sample_to_image(shared.state.current_latent)
shared.state.current_image_sampling_step = shared.state.sampling_step
image = shared.state.current_image
@@ -477,14 +494,14 @@ def create_toprow(is_img2img):
with gr.Row():
with gr.Column(scale=80):
with gr.Row():
- prompt = gr.Textbox(label="Prompt", elem_id=f"{id_part}_prompt", show_label=False, lines=2,
+ prompt = gr.Textbox(label="Prompt", elem_id=f"{id_part}_prompt", show_label=False, lines=2,
placeholder="Prompt (press Ctrl+Enter or Alt+Enter to generate)"
)
with gr.Row():
with gr.Column(scale=80):
with gr.Row():
- negative_prompt = gr.Textbox(label="Negative prompt", elem_id=f"{id_part}_neg_prompt", show_label=False, lines=2,
+ negative_prompt = gr.Textbox(label="Negative prompt", elem_id=f"{id_part}_neg_prompt", show_label=False, lines=2,
placeholder="Negative prompt (press Ctrl+Enter or Alt+Enter to generate)"
)
@@ -561,6 +578,9 @@ def apply_setting(key, value):
if value is None:
return gr.update()
+ if shared.cmd_opts.freeze_settings:
+ return gr.update()
+
# dont allow model to be swapped when model hash exists in prompt
if key == "sd_model_checkpoint" and opts.disable_weights_auto_swap:
return gr.update()
@@ -587,27 +607,29 @@ def apply_setting(key, value):
return value
-def create_ui(wrap_gradio_gpu_call):
- import modules.img2img
- import modules.txt2img
+def create_refresh_button(refresh_component, refresh_method, refreshed_args, elem_id):
+ def refresh():
+ refresh_method()
+ args = refreshed_args() if callable(refreshed_args) else refreshed_args
- def create_refresh_button(refresh_component, refresh_method, refreshed_args, elem_id):
- def refresh():
- refresh_method()
- args = refreshed_args() if callable(refreshed_args) else refreshed_args
+ for k, v in args.items():
+ setattr(refresh_component, k, v)
- for k, v in args.items():
- setattr(refresh_component, k, v)
+ return gr.update(**(args or {}))
- return gr.update(**(args or {}))
+ refresh_button = gr.Button(value=refresh_symbol, elem_id=elem_id)
+ refresh_button.click(
+ fn=refresh,
+ inputs=[],
+ outputs=[refresh_component]
+ )
+ return refresh_button
+
+
+def create_ui(wrap_gradio_gpu_call):
+ import modules.img2img
+ import modules.txt2img
- refresh_button = gr.Button(value=refresh_symbol, elem_id=elem_id)
- refresh_button.click(
- fn = refresh,
- inputs = [],
- outputs = [refresh_component]
- )
- return refresh_button
with gr.Blocks(analytics_enabled=False) as txt2img_interface:
txt2img_prompt, roll, txt2img_prompt_style, txt2img_negative_prompt, txt2img_prompt_style2, submit, _, _, txt2img_prompt_style_apply, txt2img_save_style, txt2img_paste, token_counter, token_button = create_toprow(is_img2img=False)
@@ -705,6 +727,7 @@ def create_ui(wrap_gradio_gpu_call):
firstphase_width,
firstphase_height,
] + custom_inputs,
+
outputs=[
txt2img_gallery,
generation_info,
@@ -761,6 +784,7 @@ def create_ui(wrap_gradio_gpu_call):
]
)
+ global txt2img_paste_fields
txt2img_paste_fields = [
(txt2img_prompt, "Prompt"),
(txt2img_negative_prompt, "Negative prompt"),
@@ -781,6 +805,7 @@ def create_ui(wrap_gradio_gpu_call):
(hr_options, lambda d: gr.Row.update(visible="Denoising strength" in d)),
(firstphase_width, "First pass size-1"),
(firstphase_height, "First pass size-2"),
+ *modules.scripts.scripts_txt2img.infotext_fields
]
txt2img_preview_params = [
@@ -848,8 +873,8 @@ def create_ui(wrap_gradio_gpu_call):
sampler_index = gr.Radio(label='Sampling method', choices=[x.name for x in samplers_for_img2img], value=samplers_for_img2img[0].name, type="index")
with gr.Group():
- width = gr.Slider(minimum=64, maximum=2048, step=64, label="Width", value=512)
- height = gr.Slider(minimum=64, maximum=2048, step=64, label="Height", value=512)
+ width = gr.Slider(minimum=64, maximum=2048, step=64, label="Width", value=512, elem_id="img2img_width")
+ height = gr.Slider(minimum=64, maximum=2048, step=64, label="Height", value=512, elem_id="img2img_height")
with gr.Row():
restore_faces = gr.Checkbox(label='Restore faces', value=False, visible=len(shared.face_restorers) > 1)
@@ -1030,6 +1055,7 @@ def create_ui(wrap_gradio_gpu_call):
outputs=[prompt, negative_prompt, style1, style2],
)
+ global img2img_paste_fields
img2img_paste_fields = [
(img2img_prompt, "Prompt"),
(img2img_negative_prompt, "Negative prompt"),
@@ -1046,6 +1072,7 @@ def create_ui(wrap_gradio_gpu_call):
(seed_resize_from_w, "Seed resize from-1"),
(seed_resize_from_h, "Seed resize from-2"),
(denoising_strength, "Denoising strength"),
+ *modules.scripts.scripts_img2img.infotext_fields
]
token_button.click(fn=update_token_counter, inputs=[img2img_prompt, steps], outputs=[token_counter])
@@ -1077,9 +1104,9 @@ def create_ui(wrap_gradio_gpu_call):
upscaling_resize_w = gr.Number(label="Width", value=512, precision=0)
upscaling_resize_h = gr.Number(label="Height", value=512, precision=0)
upscaling_crop = gr.Checkbox(label='Crop to fit', value=True)
-
+
with gr.Group():
- extras_upscaler_1 = gr.Radio(label='Upscaler 1', elem_id="extras_upscaler_1", choices=[x.name for x in shared.sd_upscalers], value=shared.sd_upscalers[0].name, type="index")
+ extras_upscaler_1 = gr.Radio(label='Upscaler 1', elem_id="extras_upscaler_1", choices=[x.name for x in shared.sd_upscalers], value=shared.sd_upscalers[0].name, type="index")
with gr.Group():
extras_upscaler_2 = gr.Radio(label='Upscaler 2', elem_id="extras_upscaler_2", choices=[x.name for x in shared.sd_upscalers], value=shared.sd_upscalers[0].name, type="index")
@@ -1166,15 +1193,7 @@ def create_ui(wrap_gradio_gpu_call):
inputs=[image],
outputs=[html, generation_info, html2],
)
- #images history
- images_history_switch_dict = {
- "fn":modules.generation_parameters_copypaste.connect_paste,
- "t2i":txt2img_paste_fields,
- "i2i":img2img_paste_fields
- }
-
- images_history = img_his.create_history_tabs(gr, opts, wrap_gradio_call(modules.extras.run_pnginfo), images_history_switch_dict)
-
+
with gr.Blocks() as modelmerger_interface:
with gr.Row().style(equal_height=False):
with gr.Column(variant='panel'):
@@ -1206,6 +1225,7 @@ def create_ui(wrap_gradio_gpu_call):
new_embedding_name = gr.Textbox(label="Name")
initialization_text = gr.Textbox(label="Initialization text", value="*")
nvpt = gr.Slider(label="Number of vectors per token", minimum=1, maximum=75, step=1, value=1)
+ overwrite_old_embedding = gr.Checkbox(value=False, label="Overwrite Old Embedding")
with gr.Row():
with gr.Column(scale=3):
@@ -1217,6 +1237,11 @@ def create_ui(wrap_gradio_gpu_call):
with gr.Tab(label="Create hypernetwork"):
new_hypernetwork_name = gr.Textbox(label="Name")
new_hypernetwork_sizes = gr.CheckboxGroup(label="Modules", value=["768", "320", "640", "1280"], choices=["768", "320", "640", "1280"])
+ new_hypernetwork_layer_structure = gr.Textbox("1, 2, 1", label="Enter hypernetwork layer structure", placeholder="1st and last digit must be 1. ex:'1, 2, 1'")
+ new_hypernetwork_activation_func = gr.Dropdown(value="relu", label="Select activation function of hypernetwork", choices=["linear", "relu", "leakyrelu", "elu", "swish"])
+ new_hypernetwork_add_layer_norm = gr.Checkbox(label="Add layer normalization")
+ new_hypernetwork_use_dropout = gr.Checkbox(label="Use dropout")
+ overwrite_old_hypernetwork = gr.Checkbox(value=False, label="Overwrite Old Hypernetwork")
with gr.Row():
with gr.Column(scale=3):
@@ -1230,14 +1255,19 @@ def create_ui(wrap_gradio_gpu_call):
process_dst = gr.Textbox(label='Destination directory')
process_width = gr.Slider(minimum=64, maximum=2048, step=64, label="Width", value=512)
process_height = gr.Slider(minimum=64, maximum=2048, step=64, label="Height", value=512)
+ preprocess_txt_action = gr.Dropdown(label='Existing Caption txt Action', value="ignore", choices=["ignore", "copy", "prepend", "append"])
with gr.Row():
process_flip = gr.Checkbox(label='Create flipped copies')
- process_split = gr.Checkbox(label='Split oversized images into two')
+ process_split = gr.Checkbox(label='Split oversized images')
process_entropy_focus = gr.Checkbox(label='Create auto focal point crop')
process_caption = gr.Checkbox(label='Use BLIP for caption')
process_caption_deepbooru = gr.Checkbox(label='Use deepbooru for caption', visible=True if cmd_opts.deepdanbooru else False)
+ with gr.Row(visible=False) as process_split_extra_row:
+ process_split_threshold = gr.Slider(label='Split image threshold', value=0.5, minimum=0.0, maximum=1.0, step=0.05)
+ process_overlap_ratio = gr.Slider(label='Split image overlap ratio', value=0.2, minimum=0.0, maximum=0.9, step=0.05)
+
with gr.Row():
with gr.Column(scale=3):
gr.HTML(value="")
@@ -1245,15 +1275,24 @@ def create_ui(wrap_gradio_gpu_call):
with gr.Column():
run_preprocess = gr.Button(value="Preprocess", variant='primary')
+ process_split.change(
+ fn=lambda show: gr_show(show),
+ inputs=[process_split],
+ outputs=[process_split_extra_row],
+ )
+
with gr.Tab(label="Train"):
- gr.HTML(value="<p style='margin-bottom: 0.7em'>Train an embedding; must specify a directory with a set of 1:1 ratio images</p>")
+ gr.HTML(value="<p style='margin-bottom: 0.7em'>Train an embedding or Hypernetwork; you must specify a directory with a set of 1:1 ratio images <a href=\"https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Textual-Inversion\" style=\"font-weight:bold;\">[wiki]</a></p>")
with gr.Row():
train_embedding_name = gr.Dropdown(label='Embedding', elem_id="train_embedding", choices=sorted(sd_hijack.model_hijack.embedding_db.word_embeddings.keys()))
create_refresh_button(train_embedding_name, sd_hijack.model_hijack.embedding_db.load_textual_inversion_embeddings, lambda: {"choices": sorted(sd_hijack.model_hijack.embedding_db.word_embeddings.keys())}, "refresh_train_embedding_name")
with gr.Row():
train_hypernetwork_name = gr.Dropdown(label='Hypernetwork', elem_id="train_hypernetwork", choices=[x for x in shared.hypernetworks.keys()])
create_refresh_button(train_hypernetwork_name, shared.reload_hypernetworks, lambda: {"choices": sorted([x for x in shared.hypernetworks.keys()])}, "refresh_train_hypernetwork_name")
- learn_rate = gr.Textbox(label='Learning rate', placeholder="Learning rate", value="0.005")
+ with gr.Row():
+ embedding_learn_rate = gr.Textbox(label='Embedding Learning rate', placeholder="Embedding Learning rate", value="0.005")
+ hypernetwork_learn_rate = gr.Textbox(label='Hypernetwork Learning rate', placeholder="Hypernetwork Learning rate", value="0.00001")
+
batch_size = gr.Number(label='Batch size', value=1, precision=0)
dataset_directory = gr.Textbox(label='Dataset directory', placeholder="Path to directory with input images")
log_directory = gr.Textbox(label='Log directory', placeholder="Path to directory where to write outputs", value="textual_inversion")
@@ -1287,6 +1326,7 @@ def create_ui(wrap_gradio_gpu_call):
new_embedding_name,
initialization_text,
nvpt,
+ overwrite_old_embedding,
],
outputs=[
train_embedding_name,
@@ -1300,6 +1340,11 @@ def create_ui(wrap_gradio_gpu_call):
inputs=[
new_hypernetwork_name,
new_hypernetwork_sizes,
+ overwrite_old_hypernetwork,
+ new_hypernetwork_layer_structure,
+ new_hypernetwork_activation_func,
+ new_hypernetwork_add_layer_norm,
+ new_hypernetwork_use_dropout
],
outputs=[
train_hypernetwork_name,
@@ -1316,11 +1361,14 @@ def create_ui(wrap_gradio_gpu_call):
process_dst,
process_width,
process_height,
+ preprocess_txt_action,
process_flip,
process_split,
process_caption,
process_caption_deepbooru,
- process_entropy_focus
+ process_split_threshold,
+ process_overlap_ratio,
+ process_entropy_focus,
],
outputs=[
ti_output,
@@ -1333,7 +1381,7 @@ def create_ui(wrap_gradio_gpu_call):
_js="start_training_textual_inversion",
inputs=[
train_embedding_name,
- learn_rate,
+ embedding_learn_rate,
batch_size,
dataset_directory,
log_directory,
@@ -1358,7 +1406,7 @@ def create_ui(wrap_gradio_gpu_call):
_js="start_training_textual_inversion",
inputs=[
train_hypernetwork_name,
- learn_rate,
+ hypernetwork_learn_rate,
batch_size,
dataset_directory,
log_directory,
@@ -1422,6 +1470,9 @@ def create_ui(wrap_gradio_gpu_call):
components = []
component_dict = {}
+ script_callbacks.ui_settings_callback()
+ opts.reorder()
+
def open_folder(f):
if not os.path.exists(f):
print(f'Folder "{f}" does not exist. After you create an image, the folder will be created.')
@@ -1447,6 +1498,8 @@ Requested path was: {f}
def run_settings(*args):
changed = 0
+ assert not shared.cmd_opts.freeze_settings, "changing settings is disabled"
+
for key, value, comp in zip(opts.data_labels.keys(), args, components):
if comp != dummy_component and not opts.same_type(value, opts.data_labels[key].default):
return f"Bad value for setting {key}: {value}; expecting {type(opts.data_labels[key].default).__name__}", opts.dumpjson()
@@ -1476,13 +1529,15 @@ Requested path was: {f}
return f'{changed} settings changed.', opts.dumpjson()
def run_settings_single(value, key):
+ assert not shared.cmd_opts.freeze_settings, "changing settings is disabled"
+
if not opts.same_type(value, opts.data_labels[key].default):
return gr.update(visible=True), opts.dumpjson()
+ oldval = opts.data.get(key, None)
if cmd_opts.hide_ui_dir_config and key in restricted_opts:
return gr.update(value=oldval), opts.dumpjson()
- oldval = opts.data.get(key, None)
opts.data[key] = value
if oldval != value:
@@ -1525,9 +1580,10 @@ Requested path was: {f}
previous_section = item.section
- gr.HTML(elem_id="settings_header_text_{}".format(item.section[0]), value='<h1 class="gr-button-lg">{}</h1>'.format(item.section[1]))
+ elem_id, text = item.section
+ gr.HTML(elem_id="settings_header_text_{}".format(elem_id), value='<h1 class="gr-button-lg">{}</h1>'.format(text))
- if k in quicksettings_names:
+ if k in quicksettings_names and not shared.cmd_opts.freeze_settings:
quicksettings_list.append((i, k, item))
components.append(dummy_component)
else:
@@ -1560,7 +1616,7 @@ Requested path was: {f}
def reload_scripts():
modules.scripts.reload_script_body_only()
- reload_javascript() # need to refresh the html page
+ reload_javascript() # need to refresh the html page
reload_script_bodies.click(
fn=reload_scripts,
@@ -1588,19 +1644,26 @@ Requested path was: {f}
(img2img_interface, "img2img", "img2img"),
(extras_interface, "Extras", "extras"),
(pnginfo_interface, "PNG Info", "pnginfo"),
- (images_history, "History", "images_history"),
(modelmerger_interface, "Checkpoint Merger", "modelmerger"),
(train_interface, "Train", "ti"),
- (settings_interface, "Settings", "settings"),
]
- with open(os.path.join(script_path, "style.css"), "r", encoding="utf8") as file:
- css = file.read()
+ interfaces += script_callbacks.ui_tabs_callback()
+
+ interfaces += [(settings_interface, "Settings", "settings")]
+
+ css = ""
+
+ for cssfile in modules.scripts.list_files_with_name("style.css"):
+ if not os.path.isfile(cssfile):
+ continue
+
+ with open(cssfile, "r", encoding="utf8") as file:
+ css += file.read() + "\n"
if os.path.exists(os.path.join(script_path, "user.css")):
with open(os.path.join(script_path, "user.css"), "r", encoding="utf8") as file:
- usercss = file.read()
- css += usercss
+ css += file.read() + "\n"
if not cmd_opts.no_progressbar_hiding:
css += css_hide_progressbar
@@ -1823,9 +1886,10 @@ def load_javascript(raw_response):
with open(os.path.join(script_path, "script.js"), "r", encoding="utf8") as jsfile:
javascript = f'<script>{jsfile.read()}</script>'
- jsdir = os.path.join(script_path, "javascript")
- for filename in sorted(os.listdir(jsdir)):
- with open(os.path.join(jsdir, filename), "r", encoding="utf8") as jsfile:
+ scripts_list = modules.scripts.list_scripts("javascript", ".js")
+
+ for basedir, filename, path in scripts_list:
+ with open(path, "r", encoding="utf8") as jsfile:
javascript += f"\n<!-- {filename} --><script>{jsfile.read()}</script>"
if cmd_opts.theme is not None:
@@ -1843,6 +1907,5 @@ def load_javascript(raw_response):
gradio.routes.templates.TemplateResponse = template_response
-reload_javascript = partial(load_javascript,
- gradio.routes.templates.TemplateResponse)
+reload_javascript = partial(load_javascript, gradio.routes.templates.TemplateResponse)
reload_javascript()
diff --git a/scripts/img2imgalt.py b/scripts/img2imgalt.py
index d438175c..88abc093 100644
--- a/scripts/img2imgalt.py
+++ b/scripts/img2imgalt.py
@@ -34,6 +34,9 @@ def find_noise_for_image(p, cond, uncond, cfg_scale, steps):
sigma_in = torch.cat([sigmas[i] * s_in] * 2)
cond_in = torch.cat([uncond, cond])
+ image_conditioning = torch.cat([p.image_conditioning] * 2)
+ cond_in = {"c_concat": [image_conditioning], "c_crossattn": [cond_in]}
+
c_out, c_in = [K.utils.append_dims(k, x_in.ndim) for k in dnw.get_scalings(sigma_in)]
t = dnw.sigma_to_t(sigma_in)
@@ -78,6 +81,9 @@ def find_noise_for_image_sigma_adjustment(p, cond, uncond, cfg_scale, steps):
sigma_in = torch.cat([sigmas[i - 1] * s_in] * 2)
cond_in = torch.cat([uncond, cond])
+ image_conditioning = torch.cat([p.image_conditioning] * 2)
+ cond_in = {"c_concat": [image_conditioning], "c_crossattn": [cond_in]}
+
c_out, c_in = [K.utils.append_dims(k, x_in.ndim) for k in dnw.get_scalings(sigma_in)]
if i == 1:
@@ -194,7 +200,7 @@ class Script(scripts.Script):
p.seed = p.seed + 1
- return sampler.sample_img2img(p, p.init_latent, noise_dt, conditioning, unconditional_conditioning)
+ return sampler.sample_img2img(p, p.init_latent, noise_dt, conditioning, unconditional_conditioning, image_conditioning=p.image_conditioning)
p.sample = sample_extra
diff --git a/scripts/outpainting_mk_2.py b/scripts/outpainting_mk_2.py
index a6468e09..2afd4aa5 100644
--- a/scripts/outpainting_mk_2.py
+++ b/scripts/outpainting_mk_2.py
@@ -172,54 +172,54 @@ class Script(scripts.Script):
if down > 0:
down = target_h - init_img.height - up
- init_image = p.init_images[0]
-
- state.job_count = (1 if left > 0 else 0) + (1 if right > 0 else 0) + (1 if up > 0 else 0) + (1 if down > 0 else 0)
-
- def expand(init, expand_pixels, is_left=False, is_right=False, is_top=False, is_bottom=False):
+ def expand(init, count, expand_pixels, is_left=False, is_right=False, is_top=False, is_bottom=False):
is_horiz = is_left or is_right
is_vert = is_top or is_bottom
pixels_horiz = expand_pixels if is_horiz else 0
pixels_vert = expand_pixels if is_vert else 0
- res_w = init.width + pixels_horiz
- res_h = init.height + pixels_vert
- process_res_w = math.ceil(res_w / 64) * 64
- process_res_h = math.ceil(res_h / 64) * 64
-
- img = Image.new("RGB", (process_res_w, process_res_h))
- img.paste(init, (pixels_horiz if is_left else 0, pixels_vert if is_top else 0))
- mask = Image.new("RGB", (process_res_w, process_res_h), "white")
- draw = ImageDraw.Draw(mask)
- draw.rectangle((
- expand_pixels + mask_blur if is_left else 0,
- expand_pixels + mask_blur if is_top else 0,
- mask.width - expand_pixels - mask_blur if is_right else res_w,
- mask.height - expand_pixels - mask_blur if is_bottom else res_h,
- ), fill="black")
-
- np_image = (np.asarray(img) / 255.0).astype(np.float64)
- np_mask = (np.asarray(mask) / 255.0).astype(np.float64)
- noised = get_matched_noise(np_image, np_mask, noise_q, color_variation)
- out = Image.fromarray(np.clip(noised * 255., 0., 255.).astype(np.uint8), mode="RGB")
-
- target_width = min(process_width, init.width + pixels_horiz) if is_horiz else img.width
- target_height = min(process_height, init.height + pixels_vert) if is_vert else img.height
-
- crop_region = (
- 0 if is_left else out.width - target_width,
- 0 if is_top else out.height - target_height,
- target_width if is_left else out.width,
- target_height if is_top else out.height,
- )
-
- image_to_process = out.crop(crop_region)
- mask = mask.crop(crop_region)
-
- p.width = target_width if is_horiz else img.width
- p.height = target_height if is_vert else img.height
- p.init_images = [image_to_process]
- p.image_mask = mask
+ images_to_process = []
+ output_images = []
+ for n in range(count):
+ res_w = init[n].width + pixels_horiz
+ res_h = init[n].height + pixels_vert
+ process_res_w = math.ceil(res_w / 64) * 64
+ process_res_h = math.ceil(res_h / 64) * 64
+
+ img = Image.new("RGB", (process_res_w, process_res_h))
+ img.paste(init[n], (pixels_horiz if is_left else 0, pixels_vert if is_top else 0))
+ mask = Image.new("RGB", (process_res_w, process_res_h), "white")
+ draw = ImageDraw.Draw(mask)
+ draw.rectangle((
+ expand_pixels + mask_blur if is_left else 0,
+ expand_pixels + mask_blur if is_top else 0,
+ mask.width - expand_pixels - mask_blur if is_right else res_w,
+ mask.height - expand_pixels - mask_blur if is_bottom else res_h,
+ ), fill="black")
+
+ np_image = (np.asarray(img) / 255.0).astype(np.float64)
+ np_mask = (np.asarray(mask) / 255.0).astype(np.float64)
+ noised = get_matched_noise(np_image, np_mask, noise_q, color_variation)
+ output_images.append(Image.fromarray(np.clip(noised * 255., 0., 255.).astype(np.uint8), mode="RGB"))
+
+ target_width = min(process_width, init[n].width + pixels_horiz) if is_horiz else img.width
+ target_height = min(process_height, init[n].height + pixels_vert) if is_vert else img.height
+ p.width = target_width if is_horiz else img.width
+ p.height = target_height if is_vert else img.height
+
+ crop_region = (
+ 0 if is_left else output_images[n].width - target_width,
+ 0 if is_top else output_images[n].height - target_height,
+ target_width if is_left else output_images[n].width,
+ target_height if is_top else output_images[n].height,
+ )
+ mask = mask.crop(crop_region)
+ p.image_mask = mask
+
+ image_to_process = output_images[n].crop(crop_region)
+ images_to_process.append(image_to_process)
+
+ p.init_images = images_to_process
latent_mask = Image.new("RGB", (p.width, p.height), "white")
draw = ImageDraw.Draw(latent_mask)
@@ -232,31 +232,52 @@ class Script(scripts.Script):
p.latent_mask = latent_mask
proc = process_images(p)
- proc_img = proc.images[0]
if initial_seed_and_info[0] is None:
initial_seed_and_info[0] = proc.seed
initial_seed_and_info[1] = proc.info
- out.paste(proc_img, (0 if is_left else out.width - proc_img.width, 0 if is_top else out.height - proc_img.height))
- out = out.crop((0, 0, res_w, res_h))
- return out
+ for n in range(count):
+ output_images[n].paste(proc.images[n], (0 if is_left else output_images[n].width - proc.images[n].width, 0 if is_top else output_images[n].height - proc.images[n].height))
+ output_images[n] = output_images[n].crop((0, 0, res_w, res_h))
- img = init_image
+ return output_images
- if left > 0:
- img = expand(img, left, is_left=True)
- if right > 0:
- img = expand(img, right, is_right=True)
- if up > 0:
- img = expand(img, up, is_top=True)
- if down > 0:
- img = expand(img, down, is_bottom=True)
+ batch_count = p.n_iter
+ batch_size = p.batch_size
+ p.n_iter = 1
+ state.job_count = batch_count * ((1 if left > 0 else 0) + (1 if right > 0 else 0) + (1 if up > 0 else 0) + (1 if down > 0 else 0))
+ all_processed_images = []
+
+ for i in range(batch_count):
+ imgs = [init_img] * batch_size
+ state.job = f"Batch {i + 1} out of {batch_count}"
+
+ if left > 0:
+ imgs = expand(imgs, batch_size, left, is_left=True)
+ if right > 0:
+ imgs = expand(imgs, batch_size, right, is_right=True)
+ if up > 0:
+ imgs = expand(imgs, batch_size, up, is_top=True)
+ if down > 0:
+ imgs = expand(imgs, batch_size, down, is_bottom=True)
- res = Processed(p, [img], initial_seed_and_info[0], initial_seed_and_info[1])
+ all_processed_images += imgs
+
+ all_images = all_processed_images
+
+ combined_grid_image = images.image_grid(all_processed_images)
+ unwanted_grid_because_of_img_count = len(all_processed_images) < 2 and opts.grid_only_if_multiple
+ if opts.return_grid and not unwanted_grid_because_of_img_count:
+ all_images = [combined_grid_image] + all_processed_images
+
+ res = Processed(p, all_images, initial_seed_and_info[0], initial_seed_and_info[1])
if opts.samples_save:
- images.save_image(img, p.outpath_samples, "", res.seed, p.prompt, opts.grid_format, info=res.info, p=p)
+ for img in all_processed_images:
+ images.save_image(img, p.outpath_samples, "", res.seed, p.prompt, opts.grid_format, info=res.info, p=p)
- return res
+ if opts.grid_save and not unwanted_grid_because_of_img_count:
+ images.save_image(combined_grid_image, p.outpath_grids, "grid", res.seed, p.prompt, opts.grid_format, info=res.info, short_filename=not opts.grid_extended_filename, grid=True, p=p)
+ return res
diff --git a/scripts/xy_grid.py b/scripts/xy_grid.py
index 5cca168a..eff0c942 100644
--- a/scripts/xy_grid.py
+++ b/scripts/xy_grid.py
@@ -89,6 +89,7 @@ def apply_checkpoint(p, x, xs):
if info is None:
raise RuntimeError(f"Unknown checkpoint: {x}")
modules.sd_models.reload_model_weights(shared.sd_model, info)
+ p.sd_model = shared.sd_model
def confirm_checkpoints(p, xs):
diff --git a/style.css b/style.css
index 26ae36a5..13a9fb07 100644
--- a/style.css
+++ b/style.css
@@ -515,3 +515,77 @@ img2maskimg, #img2maskimg > .h-60, #img2maskimg > .h-60 > div, #img2maskimg > .h
max-height: 480px !important;
min-height: 480px !important;
}
+
+/* The following handles localization for right-to-left (RTL) languages like Arabic.
+The rtl media type will only be activated by the logic in javascript/localization.js.
+If you change anything above, you need to make sure it is RTL compliant by just running
+your changes through converters like https://cssjanus.github.io/ or https://rtlcss.com/.
+Then, you will need to add the RTL counterpart only if needed in the rtl section below.*/
+@media rtl {
+ /* this part was manualy added */
+ :host {
+ direction: rtl;
+ }
+ .output-html:has(.performance), .gr-text-input {
+ direction: ltr;
+ }
+ .gr-radio, .gr-checkbox{
+ margin-left: 0.25em;
+ }
+
+ /* this part was automatically generated with few manual modifications */
+ .performance .time {
+ margin-right: unset;
+ margin-left: 0;
+ }
+ .justify-center.overflow-x-scroll {
+ justify-content: right;
+ }
+ .justify-center.overflow-x-scroll button:first-of-type {
+ margin-left: unset;
+ margin-right: auto;
+ }
+ .justify-center.overflow-x-scroll button:last-of-type {
+ margin-right: unset;
+ margin-left: auto;
+ }
+ #settings fieldset span.text-gray-500, #settings .gr-block.gr-box span.text-gray-500, #settings label.block span{
+ margin-right: unset;
+ margin-left: 8em;
+ }
+ #txt2img_progressbar, #img2img_progressbar, #ti_progressbar{
+ right: unset;
+ left: 0;
+ }
+ .progressDiv .progress{
+ padding: 0 0 0 8px;
+ text-align: left;
+ }
+ #lightboxModal{
+ left: unset;
+ right: 0;
+ }
+ .modalPrev, .modalNext{
+ border-radius: 3px 0 0 3px;
+ }
+ .modalNext {
+ right: unset;
+ left: 0;
+ border-radius: 0 3px 3px 0;
+ }
+ #imageARPreview{
+ left:unset;
+ right:0px;
+ }
+ #txt2img_skip, #img2img_skip{
+ right: unset;
+ left: 0px;
+ }
+ #context-menu{
+ box-shadow:-1px 1px 2px #CE6400;
+ }
+ .gr-box > div > div > input.gr-text-input{
+ right: unset;
+ left: 0.5em;
+ }
+}
diff --git a/webui.py b/webui.py
index 71724c3b..ade7334b 100644
--- a/webui.py
+++ b/webui.py
@@ -9,7 +9,7 @@ from fastapi.middleware.gzip import GZipMiddleware
from modules.paths import script_path
-from modules import devices, sd_samplers
+from modules import devices, sd_samplers, upscaler
import modules.codeformer_model as codeformer
import modules.extras
import modules.face_restoration
@@ -71,7 +71,13 @@ def wrap_gradio_gpu_call(func, extra_outputs=None):
return modules.ui.wrap_gradio_call(f, extra_outputs=extra_outputs)
+
def initialize():
+ if cmd_opts.ui_debug_mode:
+ shared.sd_upscalers = upscaler.UpscalerLanczos().scalers
+ modules.scripts.load_scripts()
+ return
+
modelloader.cleanup_models()
modules.sd_models.setup_model()
codeformer.setup_model(cmd_opts.codeformer_models_path)
@@ -79,9 +85,9 @@ def initialize():
shared.face_restorers.append(modules.face_restoration.FaceRestoration())
modelloader.load_upscalers()
- modules.scripts.load_scripts(os.path.join(script_path, "scripts"))
+ modules.scripts.load_scripts()
- shared.sd_model = modules.sd_models.load_model()
+ modules.sd_models.load_model()
shared.opts.onchange("sd_model_checkpoint", wrap_queued_call(lambda: modules.sd_models.reload_model_weights(shared.sd_model)))
shared.opts.onchange("sd_hypernetwork", wrap_queued_call(lambda: modules.hypernetworks.hypernetwork.load_hypernetwork(shared.opts.sd_hypernetwork)))
shared.opts.onchange("sd_hypernetwork_strength", modules.hypernetworks.hypernetwork.apply_strength)
@@ -118,7 +124,8 @@ def api_only():
api.launch(server_name="0.0.0.0" if cmd_opts.listen else "127.0.0.1", port=cmd_opts.port if cmd_opts.port else 7861)
-def webui(launch_api=False):
+def webui():
+ launch_api = cmd_opts.api
initialize()
while 1:
@@ -133,6 +140,8 @@ def webui(launch_api=False):
inbrowser=cmd_opts.autolaunch,
prevent_thread_lock=True
)
+ # after initial launch, disable --autolaunch for subsequent restarts
+ cmd_opts.autolaunch = False
app.add_middleware(GZipMiddleware, minimum_size=1000)
@@ -140,11 +149,11 @@ def webui(launch_api=False):
create_api(app)
wait_on_server(demo)
-
+
sd_samplers.set_samplers()
print('Reloading Custom Scripts')
- modules.scripts.reload_scripts(os.path.join(script_path, "scripts"))
+ modules.scripts.reload_scripts()
print('Reloading modules: modules.ui')
importlib.reload(modules.ui)
print('Refreshing Model List')
@@ -158,4 +167,4 @@ if __name__ == "__main__":
if cmd_opts.nowebui:
api_only()
else:
- webui(cmd_opts.api) \ No newline at end of file
+ webui()