mirror of
https://github.com/openvinotoolkit/stable-diffusion-webui.git
synced 2024-12-15 07:03:06 +03:00
Merge branch 'master' into fix-vram
This commit is contained in:
commit
b66aa334a9
@ -4,6 +4,21 @@ global_progressbars = {}
|
|||||||
function check_progressbar(id_part, id_progressbar, id_progressbar_span, id_interrupt, id_preview, id_gallery){
|
function check_progressbar(id_part, id_progressbar, id_progressbar_span, id_interrupt, id_preview, id_gallery){
|
||||||
var progressbar = gradioApp().getElementById(id_progressbar)
|
var progressbar = gradioApp().getElementById(id_progressbar)
|
||||||
var interrupt = gradioApp().getElementById(id_interrupt)
|
var interrupt = gradioApp().getElementById(id_interrupt)
|
||||||
|
|
||||||
|
if(opts.show_progress_in_title && progressbar && progressbar.offsetParent){
|
||||||
|
if(progressbar.innerText){
|
||||||
|
let newtitle = 'Stable Diffusion - ' + progressbar.innerText
|
||||||
|
if(document.title != newtitle){
|
||||||
|
document.title = newtitle;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
let newtitle = 'Stable Diffusion'
|
||||||
|
if(document.title != newtitle){
|
||||||
|
document.title = newtitle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(progressbar!= null && progressbar != global_progressbars[id_progressbar]){
|
if(progressbar!= null && progressbar != global_progressbars[id_progressbar]){
|
||||||
global_progressbars[id_progressbar] = progressbar
|
global_progressbars[id_progressbar] = progressbar
|
||||||
|
|
||||||
|
11
launch.py
11
launch.py
@ -19,7 +19,7 @@ clip_package = os.environ.get('CLIP_PACKAGE', "git+https://github.com/openai/CLI
|
|||||||
|
|
||||||
stable_diffusion_commit_hash = os.environ.get('STABLE_DIFFUSION_COMMIT_HASH', "69ae4b35e0a0f6ee1af8bb9a5d0016ccb27e36dc")
|
stable_diffusion_commit_hash = os.environ.get('STABLE_DIFFUSION_COMMIT_HASH', "69ae4b35e0a0f6ee1af8bb9a5d0016ccb27e36dc")
|
||||||
taming_transformers_commit_hash = os.environ.get('TAMING_TRANSFORMERS_COMMIT_HASH', "24268930bf1dce879235a7fddd0b2355b84d7ea6")
|
taming_transformers_commit_hash = os.environ.get('TAMING_TRANSFORMERS_COMMIT_HASH', "24268930bf1dce879235a7fddd0b2355b84d7ea6")
|
||||||
k_diffusion_commit_hash = os.environ.get('K_DIFFUSION_COMMIT_HASH', "a7ec1974d4ccb394c2dca275f42cd97490618924")
|
k_diffusion_commit_hash = os.environ.get('K_DIFFUSION_COMMIT_HASH', "f4e99857772fc3a126ba886aadf795a332774878")
|
||||||
codeformer_commit_hash = os.environ.get('CODEFORMER_COMMIT_HASH', "c5b4593074ba6214284d6acd5f1719b6c5d739af")
|
codeformer_commit_hash = os.environ.get('CODEFORMER_COMMIT_HASH', "c5b4593074ba6214284d6acd5f1719b6c5d739af")
|
||||||
blip_commit_hash = os.environ.get('BLIP_COMMIT_HASH', "48211a1594f1321b00f14c9f7a5b4813144b2fb9")
|
blip_commit_hash = os.environ.get('BLIP_COMMIT_HASH', "48211a1594f1321b00f14c9f7a5b4813144b2fb9")
|
||||||
|
|
||||||
@ -86,6 +86,15 @@ def git_clone(url, dir, name, commithash=None):
|
|||||||
# TODO clone into temporary dir and move if successful
|
# TODO clone into temporary dir and move if successful
|
||||||
|
|
||||||
if os.path.exists(dir):
|
if os.path.exists(dir):
|
||||||
|
if commithash is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
current_hash = run(f'"{git}" -C {dir} rev-parse HEAD', None, f"Couldn't determine {name}'s hash: {commithash}").strip()
|
||||||
|
if current_hash == commithash:
|
||||||
|
return
|
||||||
|
|
||||||
|
run(f'"{git}" -C {dir} fetch', f"Fetching updates for {name}...", f"Couldn't fetch {name}")
|
||||||
|
run(f'"{git}" -C {dir} checkout {commithash}', f"Checking out commint for {name} with hash: {commithash}...", f"Couldn't checkout commit {commithash} for {name}")
|
||||||
return
|
return
|
||||||
|
|
||||||
run(f'"{git}" clone "{url}" "{dir}"', f"Cloning {name} into {dir}...", f"Couldn't clone {name}")
|
run(f'"{git}" clone "{url}" "{dir}"', f"Cloning {name} into {dir}...", f"Couldn't clone {name}")
|
||||||
|
@ -11,9 +11,8 @@ import cv2
|
|||||||
from skimage import exposure
|
from skimage import exposure
|
||||||
|
|
||||||
import modules.sd_hijack
|
import modules.sd_hijack
|
||||||
from modules import devices, prompt_parser, masking, lowvram
|
from modules import devices, prompt_parser, masking, sd_samplers, lowvram
|
||||||
from modules.sd_hijack import model_hijack
|
from modules.sd_hijack import model_hijack
|
||||||
from modules.sd_samplers import samplers, samplers_for_img2img
|
|
||||||
from modules.shared import opts, cmd_opts, state
|
from modules.shared import opts, cmd_opts, state
|
||||||
import modules.shared as shared
|
import modules.shared as shared
|
||||||
import modules.face_restoration
|
import modules.face_restoration
|
||||||
@ -110,7 +109,7 @@ class Processed:
|
|||||||
self.width = p.width
|
self.width = p.width
|
||||||
self.height = p.height
|
self.height = p.height
|
||||||
self.sampler_index = p.sampler_index
|
self.sampler_index = p.sampler_index
|
||||||
self.sampler = samplers[p.sampler_index].name
|
self.sampler = sd_samplers.samplers[p.sampler_index].name
|
||||||
self.cfg_scale = p.cfg_scale
|
self.cfg_scale = p.cfg_scale
|
||||||
self.steps = p.steps
|
self.steps = p.steps
|
||||||
self.batch_size = p.batch_size
|
self.batch_size = p.batch_size
|
||||||
@ -265,7 +264,7 @@ def create_infotext(p, all_prompts, all_seeds, all_subseeds, comments, iteration
|
|||||||
|
|
||||||
generation_params = {
|
generation_params = {
|
||||||
"Steps": p.steps,
|
"Steps": p.steps,
|
||||||
"Sampler": samplers[p.sampler_index].name,
|
"Sampler": sd_samplers.samplers[p.sampler_index].name,
|
||||||
"CFG scale": p.cfg_scale,
|
"CFG scale": p.cfg_scale,
|
||||||
"Seed": all_seeds[index],
|
"Seed": all_seeds[index],
|
||||||
"Face restoration": (opts.face_restoration_model if p.restore_faces else None),
|
"Face restoration": (opts.face_restoration_model if p.restore_faces else None),
|
||||||
@ -360,7 +359,7 @@ def process_images(p: StableDiffusionProcessing) -> Processed:
|
|||||||
#c = p.sd_model.get_learned_conditioning(prompts)
|
#c = p.sd_model.get_learned_conditioning(prompts)
|
||||||
with devices.autocast():
|
with devices.autocast():
|
||||||
uc = prompt_parser.get_learned_conditioning(shared.sd_model, len(prompts) * [p.negative_prompt], p.steps)
|
uc = prompt_parser.get_learned_conditioning(shared.sd_model, len(prompts) * [p.negative_prompt], p.steps)
|
||||||
c = prompt_parser.get_learned_conditioning(shared.sd_model, prompts, p.steps)
|
c = prompt_parser.get_multicond_learned_conditioning(shared.sd_model, prompts, p.steps)
|
||||||
|
|
||||||
if len(model_hijack.comments) > 0:
|
if len(model_hijack.comments) > 0:
|
||||||
for comment in model_hijack.comments:
|
for comment in model_hijack.comments:
|
||||||
@ -489,7 +488,7 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing):
|
|||||||
self.firstphase_height_truncated = int(scale * self.height)
|
self.firstphase_height_truncated = int(scale * self.height)
|
||||||
|
|
||||||
def sample(self, conditioning, unconditional_conditioning, seeds, subseeds, subseed_strength):
|
def sample(self, conditioning, unconditional_conditioning, seeds, subseeds, subseed_strength):
|
||||||
self.sampler = samplers[self.sampler_index].constructor(self.sd_model)
|
self.sampler = sd_samplers.create_sampler_with_index(sd_samplers.samplers, self.sampler_index, self.sd_model)
|
||||||
|
|
||||||
if not self.enable_hr:
|
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)
|
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)
|
||||||
@ -532,7 +531,8 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing):
|
|||||||
|
|
||||||
shared.state.nextjob()
|
shared.state.nextjob()
|
||||||
|
|
||||||
self.sampler = samplers[self.sampler_index].constructor(self.sd_model)
|
self.sampler = sd_samplers.create_sampler_with_index(sd_samplers.samplers, self.sampler_index, self.sd_model)
|
||||||
|
|
||||||
noise = create_random_tensors(samples.shape[1:], seeds=seeds, subseeds=subseeds, subseed_strength=subseed_strength, seed_resize_from_h=self.seed_resize_from_h, seed_resize_from_w=self.seed_resize_from_w, p=self)
|
noise = create_random_tensors(samples.shape[1:], seeds=seeds, subseeds=subseeds, subseed_strength=subseed_strength, seed_resize_from_h=self.seed_resize_from_h, seed_resize_from_w=self.seed_resize_from_w, p=self)
|
||||||
|
|
||||||
# GC now before running the next img2img to prevent running out of memory
|
# GC now before running the next img2img to prevent running out of memory
|
||||||
@ -567,7 +567,7 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing):
|
|||||||
self.nmask = None
|
self.nmask = None
|
||||||
|
|
||||||
def init(self, all_prompts, all_seeds, all_subseeds):
|
def init(self, all_prompts, all_seeds, all_subseeds):
|
||||||
self.sampler = samplers_for_img2img[self.sampler_index].constructor(self.sd_model)
|
self.sampler = sd_samplers.create_sampler_with_index(sd_samplers.samplers_for_img2img, self.sampler_index, self.sd_model)
|
||||||
crop_region = None
|
crop_region = None
|
||||||
|
|
||||||
if self.image_mask is not None:
|
if self.image_mask is not None:
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import re
|
import re
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
from typing import List
|
||||||
import lark
|
import lark
|
||||||
|
|
||||||
# a prompt like this: "fantasy landscape with a [mountain:lake:0.25] and [an oak:a christmas tree:0.75][ in foreground::0.6][ in background:0.25] [shoddy:masterful:0.5]"
|
# a prompt like this: "fantasy landscape with a [mountain:lake:0.25] and [an oak:a christmas tree:0.75][ in foreground::0.6][ in background:0.25] [shoddy:masterful:0.5]"
|
||||||
@ -97,10 +97,26 @@ def get_learned_conditioning_prompt_schedules(prompts, steps):
|
|||||||
|
|
||||||
|
|
||||||
ScheduledPromptConditioning = namedtuple("ScheduledPromptConditioning", ["end_at_step", "cond"])
|
ScheduledPromptConditioning = namedtuple("ScheduledPromptConditioning", ["end_at_step", "cond"])
|
||||||
ScheduledPromptBatch = namedtuple("ScheduledPromptBatch", ["shape", "schedules"])
|
|
||||||
|
|
||||||
|
|
||||||
def get_learned_conditioning(model, prompts, steps):
|
def get_learned_conditioning(model, prompts, steps):
|
||||||
|
"""converts a list of prompts into a list of prompt schedules - each schedule is a list of ScheduledPromptConditioning, specifying the comdition (cond),
|
||||||
|
and the sampling step at which this condition is to be replaced by the next one.
|
||||||
|
|
||||||
|
Input:
|
||||||
|
(model, ['a red crown', 'a [blue:green:5] jeweled crown'], 20)
|
||||||
|
|
||||||
|
Output:
|
||||||
|
[
|
||||||
|
[
|
||||||
|
ScheduledPromptConditioning(end_at_step=20, cond=tensor([[-0.3886, 0.0229, -0.0523, ..., -0.4901, -0.3066, 0.0674], ..., [ 0.3317, -0.5102, -0.4066, ..., 0.4119, -0.7647, -1.0160]], device='cuda:0'))
|
||||||
|
],
|
||||||
|
[
|
||||||
|
ScheduledPromptConditioning(end_at_step=5, cond=tensor([[-0.3886, 0.0229, -0.0522, ..., -0.4901, -0.3067, 0.0673], ..., [-0.0192, 0.3867, -0.4644, ..., 0.1135, -0.3696, -0.4625]], device='cuda:0')),
|
||||||
|
ScheduledPromptConditioning(end_at_step=20, cond=tensor([[-0.3886, 0.0229, -0.0522, ..., -0.4901, -0.3067, 0.0673], ..., [-0.7352, -0.4356, -0.7888, ..., 0.6994, -0.4312, -1.2593]], device='cuda:0'))
|
||||||
|
]
|
||||||
|
]
|
||||||
|
"""
|
||||||
res = []
|
res = []
|
||||||
|
|
||||||
prompt_schedules = get_learned_conditioning_prompt_schedules(prompts, steps)
|
prompt_schedules = get_learned_conditioning_prompt_schedules(prompts, steps)
|
||||||
@ -123,13 +139,75 @@ def get_learned_conditioning(model, prompts, steps):
|
|||||||
cache[prompt] = cond_schedule
|
cache[prompt] = cond_schedule
|
||||||
res.append(cond_schedule)
|
res.append(cond_schedule)
|
||||||
|
|
||||||
return ScheduledPromptBatch((len(prompts),) + res[0][0].cond.shape, res)
|
return res
|
||||||
|
|
||||||
|
|
||||||
def reconstruct_cond_batch(c: ScheduledPromptBatch, current_step):
|
re_AND = re.compile(r"\bAND\b")
|
||||||
param = c.schedules[0][0].cond
|
re_weight = re.compile(r"^(.*?)(?:\s*:\s*([-+]?(?:\d+\.?|\d*\.\d+)))?\s*$")
|
||||||
res = torch.zeros(c.shape, device=param.device, dtype=param.dtype)
|
|
||||||
for i, cond_schedule in enumerate(c.schedules):
|
def get_multicond_prompt_list(prompts):
|
||||||
|
res_indexes = []
|
||||||
|
|
||||||
|
prompt_flat_list = []
|
||||||
|
prompt_indexes = {}
|
||||||
|
|
||||||
|
for prompt in prompts:
|
||||||
|
subprompts = re_AND.split(prompt)
|
||||||
|
|
||||||
|
indexes = []
|
||||||
|
for subprompt in subprompts:
|
||||||
|
match = re_weight.search(subprompt)
|
||||||
|
|
||||||
|
text, weight = match.groups() if match is not None else (subprompt, 1.0)
|
||||||
|
|
||||||
|
weight = float(weight) if weight is not None else 1.0
|
||||||
|
|
||||||
|
index = prompt_indexes.get(text, None)
|
||||||
|
if index is None:
|
||||||
|
index = len(prompt_flat_list)
|
||||||
|
prompt_flat_list.append(text)
|
||||||
|
prompt_indexes[text] = index
|
||||||
|
|
||||||
|
indexes.append((index, weight))
|
||||||
|
|
||||||
|
res_indexes.append(indexes)
|
||||||
|
|
||||||
|
return res_indexes, prompt_flat_list, prompt_indexes
|
||||||
|
|
||||||
|
|
||||||
|
class ComposableScheduledPromptConditioning:
|
||||||
|
def __init__(self, schedules, weight=1.0):
|
||||||
|
self.schedules: List[ScheduledPromptConditioning] = schedules
|
||||||
|
self.weight: float = weight
|
||||||
|
|
||||||
|
|
||||||
|
class MulticondLearnedConditioning:
|
||||||
|
def __init__(self, shape, batch):
|
||||||
|
self.shape: tuple = shape # the shape field is needed to send this object to DDIM/PLMS
|
||||||
|
self.batch: List[List[ComposableScheduledPromptConditioning]] = batch
|
||||||
|
|
||||||
|
def get_multicond_learned_conditioning(model, prompts, steps) -> MulticondLearnedConditioning:
|
||||||
|
"""same as get_learned_conditioning, but returns a list of ScheduledPromptConditioning along with the weight objects for each prompt.
|
||||||
|
For each prompt, the list is obtained by splitting the prompt using the AND separator.
|
||||||
|
|
||||||
|
https://energy-based-model.github.io/Compositional-Visual-Generation-with-Composable-Diffusion-Models/
|
||||||
|
"""
|
||||||
|
|
||||||
|
res_indexes, prompt_flat_list, prompt_indexes = get_multicond_prompt_list(prompts)
|
||||||
|
|
||||||
|
learned_conditioning = get_learned_conditioning(model, prompt_flat_list, steps)
|
||||||
|
|
||||||
|
res = []
|
||||||
|
for indexes in res_indexes:
|
||||||
|
res.append([ComposableScheduledPromptConditioning(learned_conditioning[i], weight) for i, weight in indexes])
|
||||||
|
|
||||||
|
return MulticondLearnedConditioning(shape=(len(prompts),), batch=res)
|
||||||
|
|
||||||
|
|
||||||
|
def reconstruct_cond_batch(c: List[List[ScheduledPromptConditioning]], current_step):
|
||||||
|
param = c[0][0].cond
|
||||||
|
res = torch.zeros((len(c),) + param.shape, device=param.device, dtype=param.dtype)
|
||||||
|
for i, cond_schedule in enumerate(c):
|
||||||
target_index = 0
|
target_index = 0
|
||||||
for current, (end_at, cond) in enumerate(cond_schedule):
|
for current, (end_at, cond) in enumerate(cond_schedule):
|
||||||
if current_step <= end_at:
|
if current_step <= end_at:
|
||||||
@ -140,6 +218,30 @@ def reconstruct_cond_batch(c: ScheduledPromptBatch, current_step):
|
|||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
def reconstruct_multicond_batch(c: MulticondLearnedConditioning, current_step):
|
||||||
|
param = c.batch[0][0].schedules[0].cond
|
||||||
|
|
||||||
|
tensors = []
|
||||||
|
conds_list = []
|
||||||
|
|
||||||
|
for batch_no, composable_prompts in enumerate(c.batch):
|
||||||
|
conds_for_batch = []
|
||||||
|
|
||||||
|
for cond_index, composable_prompt in enumerate(composable_prompts):
|
||||||
|
target_index = 0
|
||||||
|
for current, (end_at, cond) in enumerate(composable_prompt.schedules):
|
||||||
|
if current_step <= end_at:
|
||||||
|
target_index = current
|
||||||
|
break
|
||||||
|
|
||||||
|
conds_for_batch.append((len(tensors), composable_prompt.weight))
|
||||||
|
tensors.append(composable_prompt.schedules[target_index].cond)
|
||||||
|
|
||||||
|
conds_list.append(conds_for_batch)
|
||||||
|
|
||||||
|
return conds_list, torch.stack(tensors).to(device=param.device, dtype=param.dtype)
|
||||||
|
|
||||||
|
|
||||||
re_attention = re.compile(r"""
|
re_attention = re.compile(r"""
|
||||||
\\\(|
|
\\\(|
|
||||||
\\\)|
|
\\\)|
|
||||||
|
@ -13,31 +13,57 @@ from modules.shared import opts, cmd_opts, state
|
|||||||
import modules.shared as shared
|
import modules.shared as shared
|
||||||
|
|
||||||
|
|
||||||
SamplerData = namedtuple('SamplerData', ['name', 'constructor', 'aliases'])
|
SamplerData = namedtuple('SamplerData', ['name', 'constructor', 'aliases', 'options'])
|
||||||
|
|
||||||
samplers_k_diffusion = [
|
samplers_k_diffusion = [
|
||||||
('Euler a', 'sample_euler_ancestral', ['k_euler_a']),
|
('Euler a', 'sample_euler_ancestral', ['k_euler_a'], {}),
|
||||||
('Euler', 'sample_euler', ['k_euler']),
|
('Euler', 'sample_euler', ['k_euler'], {}),
|
||||||
('LMS', 'sample_lms', ['k_lms']),
|
('LMS', 'sample_lms', ['k_lms'], {}),
|
||||||
('Heun', 'sample_heun', ['k_heun']),
|
('Heun', 'sample_heun', ['k_heun'], {}),
|
||||||
('DPM2', 'sample_dpm_2', ['k_dpm_2']),
|
('DPM2', 'sample_dpm_2', ['k_dpm_2'], {}),
|
||||||
('DPM2 a', 'sample_dpm_2_ancestral', ['k_dpm_2_a']),
|
('DPM2 a', 'sample_dpm_2_ancestral', ['k_dpm_2_a'], {}),
|
||||||
('DPM fast', 'sample_dpm_fast', ['k_dpm_fast']),
|
('DPM fast', 'sample_dpm_fast', ['k_dpm_fast'], {}),
|
||||||
('DPM adaptive', 'sample_dpm_adaptive', ['k_dpm_ad']),
|
('DPM adaptive', 'sample_dpm_adaptive', ['k_dpm_ad'], {}),
|
||||||
|
('LMS Karras', 'sample_lms', ['k_lms_ka'], {'scheduler': 'karras'}),
|
||||||
|
('DPM2 Karras', 'sample_dpm_2', ['k_dpm_2_ka'], {'scheduler': 'karras'}),
|
||||||
|
('DPM2 a Karras', 'sample_dpm_2_ancestral', ['k_dpm_2_a_ka'], {'scheduler': 'karras'}),
|
||||||
]
|
]
|
||||||
|
|
||||||
samplers_data_k_diffusion = [
|
samplers_data_k_diffusion = [
|
||||||
SamplerData(label, lambda model, funcname=funcname: KDiffusionSampler(funcname, model), aliases)
|
SamplerData(label, lambda model, funcname=funcname: KDiffusionSampler(funcname, model), aliases, options)
|
||||||
for label, funcname, aliases in samplers_k_diffusion
|
for label, funcname, aliases, options in samplers_k_diffusion
|
||||||
if hasattr(k_diffusion.sampling, funcname)
|
if hasattr(k_diffusion.sampling, funcname)
|
||||||
]
|
]
|
||||||
|
|
||||||
samplers = [
|
all_samplers = [
|
||||||
*samplers_data_k_diffusion,
|
*samplers_data_k_diffusion,
|
||||||
SamplerData('DDIM', lambda model: VanillaStableDiffusionSampler(ldm.models.diffusion.ddim.DDIMSampler, model), []),
|
SamplerData('DDIM', lambda model: VanillaStableDiffusionSampler(ldm.models.diffusion.ddim.DDIMSampler, model), [], {}),
|
||||||
SamplerData('PLMS', lambda model: VanillaStableDiffusionSampler(ldm.models.diffusion.plms.PLMSSampler, model), []),
|
SamplerData('PLMS', lambda model: VanillaStableDiffusionSampler(ldm.models.diffusion.plms.PLMSSampler, model), [], {}),
|
||||||
]
|
]
|
||||||
samplers_for_img2img = [x for x in samplers if x.name not in ['PLMS', 'DPM fast', 'DPM adaptive']]
|
|
||||||
|
samplers = []
|
||||||
|
samplers_for_img2img = []
|
||||||
|
|
||||||
|
|
||||||
|
def create_sampler_with_index(list_of_configs, index, model):
|
||||||
|
config = list_of_configs[index]
|
||||||
|
sampler = config.constructor(model)
|
||||||
|
sampler.config = config
|
||||||
|
|
||||||
|
return sampler
|
||||||
|
|
||||||
|
|
||||||
|
def set_samplers():
|
||||||
|
global samplers, samplers_for_img2img
|
||||||
|
|
||||||
|
hidden = set(opts.hide_samplers)
|
||||||
|
hidden_img2img = set(opts.hide_samplers + ['PLMS', 'DPM fast', 'DPM adaptive'])
|
||||||
|
|
||||||
|
samplers = [x for x in all_samplers if x.name not in hidden]
|
||||||
|
samplers_for_img2img = [x for x in all_samplers if x.name not in hidden_img2img]
|
||||||
|
|
||||||
|
|
||||||
|
set_samplers()
|
||||||
|
|
||||||
sampler_extra_params = {
|
sampler_extra_params = {
|
||||||
'sample_euler': ['s_churn', 's_tmin', 's_tmax', 's_noise'],
|
'sample_euler': ['s_churn', 's_tmin', 's_tmax', 's_noise'],
|
||||||
@ -104,14 +130,18 @@ class VanillaStableDiffusionSampler:
|
|||||||
self.step = 0
|
self.step = 0
|
||||||
self.eta = None
|
self.eta = None
|
||||||
self.default_eta = 0.0
|
self.default_eta = 0.0
|
||||||
|
self.config = None
|
||||||
|
|
||||||
def number_of_needed_noises(self, p):
|
def number_of_needed_noises(self, p):
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def p_sample_ddim_hook(self, x_dec, cond, ts, unconditional_conditioning, *args, **kwargs):
|
def p_sample_ddim_hook(self, x_dec, cond, ts, unconditional_conditioning, *args, **kwargs):
|
||||||
cond = prompt_parser.reconstruct_cond_batch(cond, self.step)
|
conds_list, tensor = prompt_parser.reconstruct_multicond_batch(cond, self.step)
|
||||||
unconditional_conditioning = prompt_parser.reconstruct_cond_batch(unconditional_conditioning, self.step)
|
unconditional_conditioning = prompt_parser.reconstruct_cond_batch(unconditional_conditioning, self.step)
|
||||||
|
|
||||||
|
assert all([len(conds) == 1 for conds in conds_list]), 'composition via AND is not supported for DDIM/PLMS samplers'
|
||||||
|
cond = tensor
|
||||||
|
|
||||||
if self.mask is not None:
|
if self.mask is not None:
|
||||||
img_orig = self.sampler.model.q_sample(self.init_latent, ts)
|
img_orig = self.sampler.model.q_sample(self.init_latent, ts)
|
||||||
x_dec = img_orig * self.mask + self.nmask * x_dec
|
x_dec = img_orig * self.mask + self.nmask * x_dec
|
||||||
@ -183,19 +213,31 @@ class CFGDenoiser(torch.nn.Module):
|
|||||||
self.step = 0
|
self.step = 0
|
||||||
|
|
||||||
def forward(self, x, sigma, uncond, cond, cond_scale):
|
def forward(self, x, sigma, uncond, cond, cond_scale):
|
||||||
cond = prompt_parser.reconstruct_cond_batch(cond, self.step)
|
conds_list, tensor = prompt_parser.reconstruct_multicond_batch(cond, self.step)
|
||||||
uncond = prompt_parser.reconstruct_cond_batch(uncond, self.step)
|
uncond = prompt_parser.reconstruct_cond_batch(uncond, self.step)
|
||||||
|
|
||||||
|
batch_size = len(conds_list)
|
||||||
|
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])
|
||||||
|
sigma_in = torch.cat([torch.stack([sigma[i] for _ in range(n)]) for i, n in enumerate(repeats)] + [sigma])
|
||||||
|
cond_in = torch.cat([tensor, uncond])
|
||||||
|
|
||||||
if shared.batch_cond_uncond:
|
if shared.batch_cond_uncond:
|
||||||
x_in = torch.cat([x] * 2)
|
x_out = self.inner_model(x_in, sigma_in, cond=cond_in)
|
||||||
sigma_in = torch.cat([sigma] * 2)
|
|
||||||
cond_in = torch.cat([uncond, cond])
|
|
||||||
uncond, cond = self.inner_model(x_in, sigma_in, cond=cond_in).chunk(2)
|
|
||||||
denoised = uncond + (cond - uncond) * cond_scale
|
|
||||||
else:
|
else:
|
||||||
uncond = self.inner_model(x, sigma, cond=uncond)
|
x_out = torch.zeros_like(x_in)
|
||||||
cond = self.inner_model(x, sigma, cond=cond)
|
for batch_offset in range(0, x_out.shape[0], batch_size):
|
||||||
denoised = uncond + (cond - uncond) * cond_scale
|
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])
|
||||||
|
|
||||||
|
denoised_uncond = x_out[-batch_size:]
|
||||||
|
denoised = torch.clone(denoised_uncond)
|
||||||
|
|
||||||
|
for i, conds in enumerate(conds_list):
|
||||||
|
for cond_index, weight in conds:
|
||||||
|
denoised[i] += (x_out[cond_index] - denoised_uncond[i]) * (weight * cond_scale)
|
||||||
|
|
||||||
if self.mask is not None:
|
if self.mask is not None:
|
||||||
denoised = self.init_latent * self.mask + self.nmask * denoised
|
denoised = self.init_latent * self.mask + self.nmask * denoised
|
||||||
@ -250,6 +292,7 @@ class KDiffusionSampler:
|
|||||||
self.stop_at = None
|
self.stop_at = None
|
||||||
self.eta = None
|
self.eta = None
|
||||||
self.default_eta = 1.0
|
self.default_eta = 1.0
|
||||||
|
self.config = None
|
||||||
|
|
||||||
def callback_state(self, d):
|
def callback_state(self, d):
|
||||||
store_latent(d["denoised"])
|
store_latent(d["denoised"])
|
||||||
@ -315,8 +358,11 @@ class KDiffusionSampler:
|
|||||||
|
|
||||||
if p.sampler_noise_scheduler_override:
|
if p.sampler_noise_scheduler_override:
|
||||||
sigmas = p.sampler_noise_scheduler_override(steps)
|
sigmas = p.sampler_noise_scheduler_override(steps)
|
||||||
|
elif self.config is not None and self.config.options.get('scheduler', None) == 'karras':
|
||||||
|
sigmas = k_diffusion.sampling.get_sigmas_karras(n=steps, sigma_min=0.1, sigma_max=10, device=shared.device)
|
||||||
else:
|
else:
|
||||||
sigmas = self.model_wrap.get_sigmas(steps)
|
sigmas = self.model_wrap.get_sigmas(steps)
|
||||||
|
|
||||||
x = x * sigmas[0]
|
x = x * sigmas[0]
|
||||||
|
|
||||||
extra_params_kwargs = self.initialize(p)
|
extra_params_kwargs = self.initialize(p)
|
||||||
|
@ -13,6 +13,7 @@ import modules.memmon
|
|||||||
import modules.sd_models
|
import modules.sd_models
|
||||||
import modules.styles
|
import modules.styles
|
||||||
import modules.devices as devices
|
import modules.devices as devices
|
||||||
|
from modules import sd_samplers
|
||||||
from modules.paths import script_path, sd_path
|
from modules.paths import script_path, sd_path
|
||||||
|
|
||||||
sd_model_file = os.path.join(script_path, 'model.ckpt')
|
sd_model_file = os.path.join(script_path, 'model.ckpt')
|
||||||
@ -55,7 +56,7 @@ parser.add_argument("--hide-ui-dir-config", action='store_true', help="hide dire
|
|||||||
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("--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-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)
|
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)
|
||||||
parser.add_argument("--gradio-img2img-tool", type=str, help='gradio image uploader tool: can be either editor for ctopping, or color-sketch for drawing', choices=["color-sketch", "editor"], default="color-sketch")
|
parser.add_argument("--gradio-img2img-tool", type=str, help='gradio image uploader tool: can be either editor for ctopping, or color-sketch for drawing', choices=["color-sketch", "editor"], default="editor")
|
||||||
parser.add_argument("--opt-channelslast", action='store_true', help="change memory type for stable diffusion to channels last")
|
parser.add_argument("--opt-channelslast", action='store_true', help="change memory type for stable diffusion to channels last")
|
||||||
parser.add_argument("--styles-file", type=str, help="filename to use for styles", default=os.path.join(script_path, 'styles.csv'))
|
parser.add_argument("--styles-file", type=str, help="filename to use for styles", default=os.path.join(script_path, 'styles.csv'))
|
||||||
parser.add_argument("--autolaunch", action='store_true', help="open the webui URL in the system's default browser upon launch", default=False)
|
parser.add_argument("--autolaunch", action='store_true', help="open the webui URL in the system's default browser upon launch", default=False)
|
||||||
@ -235,9 +236,11 @@ options_templates.update(options_section(('ui', "User interface"), {
|
|||||||
"font": OptionInfo("", "Font for image grids that have text"),
|
"font": OptionInfo("", "Font for image grids that have text"),
|
||||||
"js_modal_lightbox": OptionInfo(True, "Enable full page image viewer"),
|
"js_modal_lightbox": OptionInfo(True, "Enable full page image viewer"),
|
||||||
"js_modal_lightbox_initialy_zoomed": OptionInfo(True, "Show images zoomed in by default in full page image viewer"),
|
"js_modal_lightbox_initialy_zoomed": OptionInfo(True, "Show images zoomed in by default in full page image viewer"),
|
||||||
|
"show_progress_in_title": OptionInfo(True, "Show generation progress in window title."),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
options_templates.update(options_section(('sampler-params', "Sampler parameters"), {
|
options_templates.update(options_section(('sampler-params', "Sampler parameters"), {
|
||||||
|
"hide_samplers": OptionInfo([], "Hide samplers in user interface (requires restart)", gr.CheckboxGroup, lambda: {"choices": [x.name for x in sd_samplers.all_samplers]}),
|
||||||
"eta_ddim": OptionInfo(0.0, "eta (noise multiplier) for DDIM", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}),
|
"eta_ddim": OptionInfo(0.0, "eta (noise multiplier) for DDIM", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}),
|
||||||
"eta_ancestral": OptionInfo(1.0, "eta (noise multiplier) for ancestral samplers", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}),
|
"eta_ancestral": OptionInfo(1.0, "eta (noise multiplier) for ancestral samplers", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}),
|
||||||
"ddim_discretize": OptionInfo('uniform', "img2img DDIM discretize", gr.Radio, {"choices": ['uniform', 'quad']}),
|
"ddim_discretize": OptionInfo('uniform', "img2img DDIM discretize", gr.Radio, {"choices": ['uniform', 'quad']}),
|
||||||
@ -246,6 +249,7 @@ options_templates.update(options_section(('sampler-params', "Sampler parameters"
|
|||||||
's_noise': OptionInfo(1.0, "sigma noise", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}),
|
's_noise': OptionInfo(1.0, "sigma noise", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|
||||||
class Options:
|
class Options:
|
||||||
data = None
|
data = None
|
||||||
data_labels = options_templates
|
data_labels = options_templates
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import os
|
import os
|
||||||
from PIL import Image, ImageOps
|
from PIL import Image, ImageOps
|
||||||
|
import platform
|
||||||
|
import sys
|
||||||
import tqdm
|
import tqdm
|
||||||
|
|
||||||
from modules import shared, images
|
from modules import shared, images
|
||||||
@ -10,7 +12,7 @@ def preprocess(process_src, process_dst, process_flip, process_split, process_ca
|
|||||||
src = os.path.abspath(process_src)
|
src = os.path.abspath(process_src)
|
||||||
dst = os.path.abspath(process_dst)
|
dst = os.path.abspath(process_dst)
|
||||||
|
|
||||||
assert src != dst, 'same directory specified as source and desitnation'
|
assert src != dst, 'same directory specified as source and destination'
|
||||||
|
|
||||||
os.makedirs(dst, exist_ok=True)
|
os.makedirs(dst, exist_ok=True)
|
||||||
|
|
||||||
@ -25,6 +27,7 @@ def preprocess(process_src, process_dst, process_flip, process_split, process_ca
|
|||||||
def save_pic_with_caption(image, index):
|
def save_pic_with_caption(image, index):
|
||||||
if process_caption:
|
if process_caption:
|
||||||
caption = "-" + shared.interrogator.generate_caption(image)
|
caption = "-" + shared.interrogator.generate_caption(image)
|
||||||
|
caption = sanitize_caption(os.path.join(dst, f"{index:05}-{subindex[0]}"), caption, ".png")
|
||||||
else:
|
else:
|
||||||
caption = filename
|
caption = filename
|
||||||
caption = os.path.splitext(caption)[0]
|
caption = os.path.splitext(caption)[0]
|
||||||
@ -75,3 +78,27 @@ def preprocess(process_src, process_dst, process_flip, process_split, process_ca
|
|||||||
|
|
||||||
if process_caption:
|
if process_caption:
|
||||||
shared.interrogator.send_blip_to_ram()
|
shared.interrogator.send_blip_to_ram()
|
||||||
|
|
||||||
|
def sanitize_caption(base_path, original_caption, suffix):
|
||||||
|
operating_system = platform.system().lower()
|
||||||
|
if (operating_system == "windows"):
|
||||||
|
invalid_path_characters = "\\/:*?\"<>|"
|
||||||
|
max_path_length = 259
|
||||||
|
else:
|
||||||
|
invalid_path_characters = "/" #linux/macos
|
||||||
|
max_path_length = 1023
|
||||||
|
caption = original_caption
|
||||||
|
for invalid_character in invalid_path_characters:
|
||||||
|
caption = caption.replace(invalid_character, "")
|
||||||
|
fixed_path_length = len(base_path) + len(suffix)
|
||||||
|
if fixed_path_length + len(caption) <= max_path_length:
|
||||||
|
return caption
|
||||||
|
caption_tokens = caption.split()
|
||||||
|
new_caption = ""
|
||||||
|
for token in caption_tokens:
|
||||||
|
last_caption = new_caption
|
||||||
|
new_caption = new_caption + token + " "
|
||||||
|
if (len(new_caption) + fixed_path_length - 1 > max_path_length):
|
||||||
|
break
|
||||||
|
print(f"\nPath will be too long. Truncated caption: {original_caption}\nto: {last_caption}", file=sys.stderr)
|
||||||
|
return last_caption.strip()
|
||||||
|
@ -34,7 +34,7 @@ import modules.gfpgan_model
|
|||||||
import modules.codeformer_model
|
import modules.codeformer_model
|
||||||
import modules.styles
|
import modules.styles
|
||||||
import modules.generation_parameters_copypaste
|
import modules.generation_parameters_copypaste
|
||||||
from modules.prompt_parser import get_learned_conditioning_prompt_schedules
|
from modules import prompt_parser
|
||||||
from modules.images import apply_filename_pattern, get_next_sequence_number
|
from modules.images import apply_filename_pattern, get_next_sequence_number
|
||||||
import modules.textual_inversion.ui
|
import modules.textual_inversion.ui
|
||||||
|
|
||||||
@ -394,7 +394,9 @@ def connect_reuse_seed(seed: gr.Number, reuse_seed: gr.Button, generation_info:
|
|||||||
|
|
||||||
def update_token_counter(text, steps):
|
def update_token_counter(text, steps):
|
||||||
try:
|
try:
|
||||||
prompt_schedules = get_learned_conditioning_prompt_schedules([text], steps)
|
_, prompt_flat_list, _ = prompt_parser.get_multicond_prompt_list([text])
|
||||||
|
prompt_schedules = prompt_parser.get_learned_conditioning_prompt_schedules(prompt_flat_list, steps)
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
# a parsing error can happen here during typing, and we don't want to bother the user with
|
# a parsing error can happen here during typing, and we don't want to bother the user with
|
||||||
# messages related to it in console
|
# messages related to it in console
|
||||||
@ -1210,6 +1212,7 @@ def create_ui(wrap_gradio_gpu_call):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def request_restart():
|
def request_restart():
|
||||||
|
shared.state.interrupt()
|
||||||
settings_interface.gradio_ref.do_restart = True
|
settings_interface.gradio_ref.do_restart = True
|
||||||
|
|
||||||
restart_gradio.click(
|
restart_gradio.click(
|
||||||
|
@ -8,7 +8,6 @@ import gradio as gr
|
|||||||
|
|
||||||
from modules import processing, shared, sd_samplers, prompt_parser
|
from modules import processing, shared, sd_samplers, prompt_parser
|
||||||
from modules.processing import Processed
|
from modules.processing import Processed
|
||||||
from modules.sd_samplers import samplers
|
|
||||||
from modules.shared import opts, cmd_opts, state
|
from modules.shared import opts, cmd_opts, state
|
||||||
|
|
||||||
import torch
|
import torch
|
||||||
@ -159,7 +158,7 @@ class Script(scripts.Script):
|
|||||||
|
|
||||||
combined_noise = ((1 - randomness) * rec_noise + randomness * rand_noise) / ((randomness**2 + (1-randomness)**2) ** 0.5)
|
combined_noise = ((1 - randomness) * rec_noise + randomness * rand_noise) / ((randomness**2 + (1-randomness)**2) ** 0.5)
|
||||||
|
|
||||||
sampler = samplers[p.sampler_index].constructor(p.sd_model)
|
sampler = sd_samplers.create_sampler_with_index(sd_samplers.samplers, p.sampler_index, p.sd_model)
|
||||||
|
|
||||||
sigmas = sampler.model_wrap.get_sigmas(p.steps)
|
sigmas = sampler.model_wrap.get_sigmas(p.steps)
|
||||||
|
|
||||||
|
@ -85,8 +85,11 @@ def get_matched_noise(_np_src_image, np_mask_rgb, noise_q=1, color_variation=0.0
|
|||||||
src_dist = np.absolute(src_fft)
|
src_dist = np.absolute(src_fft)
|
||||||
src_phase = src_fft / src_dist
|
src_phase = src_fft / src_dist
|
||||||
|
|
||||||
|
# create a generator with a static seed to make outpainting deterministic / only follow global seed
|
||||||
|
rng = np.random.default_rng(0)
|
||||||
|
|
||||||
noise_window = _get_gaussian_window(width, height, mode=1) # start with simple gaussian noise
|
noise_window = _get_gaussian_window(width, height, mode=1) # start with simple gaussian noise
|
||||||
noise_rgb = np.random.random_sample((width, height, num_channels))
|
noise_rgb = rng.random((width, height, num_channels))
|
||||||
noise_grey = (np.sum(noise_rgb, axis=2) / 3.)
|
noise_grey = (np.sum(noise_rgb, axis=2) / 3.)
|
||||||
noise_rgb *= color_variation # the colorfulness of the starting noise is blended to greyscale with a parameter
|
noise_rgb *= color_variation # the colorfulness of the starting noise is blended to greyscale with a parameter
|
||||||
for c in range(num_channels):
|
for c in range(num_channels):
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from copy import copy
|
from copy import copy
|
||||||
from itertools import permutations
|
from itertools import permutations, chain
|
||||||
import random
|
import random
|
||||||
|
import csv
|
||||||
|
from io import StringIO
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
@ -168,7 +169,6 @@ re_range_float = re.compile(r"\s*([+-]?\s*\d+(?:.\d*)?)\s*-\s*([+-]?\s*\d+(?:.\d
|
|||||||
re_range_count = re.compile(r"\s*([+-]?\s*\d+)\s*-\s*([+-]?\s*\d+)(?:\s*\[(\d+)\s*\])?\s*")
|
re_range_count = re.compile(r"\s*([+-]?\s*\d+)\s*-\s*([+-]?\s*\d+)(?:\s*\[(\d+)\s*\])?\s*")
|
||||||
re_range_count_float = re.compile(r"\s*([+-]?\s*\d+(?:.\d*)?)\s*-\s*([+-]?\s*\d+(?:.\d*)?)(?:\s*\[(\d+(?:.\d*)?)\s*\])?\s*")
|
re_range_count_float = re.compile(r"\s*([+-]?\s*\d+(?:.\d*)?)\s*-\s*([+-]?\s*\d+(?:.\d*)?)(?:\s*\[(\d+(?:.\d*)?)\s*\])?\s*")
|
||||||
|
|
||||||
|
|
||||||
class Script(scripts.Script):
|
class Script(scripts.Script):
|
||||||
def title(self):
|
def title(self):
|
||||||
return "X/Y plot"
|
return "X/Y plot"
|
||||||
@ -197,7 +197,7 @@ class Script(scripts.Script):
|
|||||||
if opt.label == 'Nothing':
|
if opt.label == 'Nothing':
|
||||||
return [0]
|
return [0]
|
||||||
|
|
||||||
valslist = [x.strip() for x in vals.split(",")]
|
valslist = list(map(str.strip,chain.from_iterable(csv.reader(StringIO(vals)))))
|
||||||
|
|
||||||
if opt.type == int:
|
if opt.type == int:
|
||||||
valslist_ext = []
|
valslist_ext = []
|
||||||
|
7
webui.py
7
webui.py
@ -2,11 +2,12 @@ import os
|
|||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
import importlib
|
import importlib
|
||||||
from modules import devices
|
|
||||||
from modules.paths import script_path
|
|
||||||
import signal
|
import signal
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
|
from modules.paths import script_path
|
||||||
|
|
||||||
|
from modules import devices, sd_samplers
|
||||||
import modules.codeformer_model as codeformer
|
import modules.codeformer_model as codeformer
|
||||||
import modules.extras
|
import modules.extras
|
||||||
import modules.face_restoration
|
import modules.face_restoration
|
||||||
@ -109,6 +110,8 @@ def webui():
|
|||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
break
|
break
|
||||||
|
|
||||||
|
sd_samplers.set_samplers()
|
||||||
|
|
||||||
print('Reloading Custom Scripts')
|
print('Reloading Custom Scripts')
|
||||||
modules.scripts.reload_scripts(os.path.join(script_path, "scripts"))
|
modules.scripts.reload_scripts(os.path.join(script_path, "scripts"))
|
||||||
print('Reloading modules: modules.ui')
|
print('Reloading modules: modules.ui')
|
||||||
|
Loading…
Reference in New Issue
Block a user