Skip to content

Commit

Permalink
Merge pull request #3682 from vladmandic/dev
Browse files Browse the repository at this point in the history
refresh master
  • Loading branch information
vladmandic authored Jan 2, 2025
2 parents c4ecee3 + dad3b11 commit 3f36089
Show file tree
Hide file tree
Showing 13 changed files with 49 additions and 30 deletions.
10 changes: 8 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Change Log for SD.Next

## Update for 2025-01-01
## Update for 2025-01-02

- [Allegro Video](https://huggingface.co/rhymes-ai/Allegro)
- optimizations: full offload and quantization support
Expand All @@ -15,11 +15,17 @@
- update installer messages
- **Detailer**:
- add explicit detailer steps setting
- **SysInfo**:
- update to collected data and benchmarks
- **Fixes**:
- explict clear caches on model load
- lock adetailer commit: `#a89c01d`
- xyzgrid fix progress calculation
- xyzgrid progress calculation
- xyzgrid detailer
- vae tiling use default value if not set
- sd35 img2img
- samplers test for scale noise before using
- scheduler api

## Update for 2024-12-31

Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@ All individual features are not listed here, instead check [ChangeLog](CHANGELOG
- Multiplatform!
**Windows | Linux | MacOS | nVidia | AMD | IntelArc/IPEX | DirectML | OpenVINO | ONNX+Olive | ZLUDA**
- Platform specific autodetection and tuning performed on install
- Optimized processing with latest `torch` developments with built-in support for `torch.compile`
and multiple compile backends: *Triton, StableFast, DeepCache, NNCF, OneDiff*
- Optimized processing with latest `torch` developments with built-in support for model compile, quantize and compress
Compile backends: *Triton | StableFast | DeepCache | OneDiff*
Quantization and compression methods: *BitsAndBytes | TorchAO | Optimum-Quanto | NNCF*
- Built-in queue management
- Built in installer with automatic updates and dependency management
- Mobile compatible
Expand Down
2 changes: 1 addition & 1 deletion extensions-builtin/sd-extension-system-info
4 changes: 4 additions & 0 deletions modules/api/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ def __init__(self, app: FastAPI, queue_lock: Lock):
# gallery api
gallery.register_api(app)

# compatibility api
self.text2imgapi = self.generate.post_text2img
self.img2imgapi = self.generate.post_img2img

def add_api_route(self, path: str, endpoint, **kwargs):
if (shared.cmd_opts.auth or shared.cmd_opts.auth_file) and shared.cmd_opts.api_only:
return self.app.add_api_route(path, endpoint, dependencies=[Depends(self.auth)], **kwargs)
Expand Down
10 changes: 3 additions & 7 deletions modules/api/models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import inspect
from typing import Any, Optional, Dict, List, Type, Callable
from typing import Any, Optional, Dict, List, Type, Callable, Union
from pydantic import BaseModel, Field, create_model # pylint: disable=no-name-in-module
from inflection import underscore
from modules.processing import StableDiffusionProcessingTxt2Img, StableDiffusionProcessingImg2Img
Expand Down Expand Up @@ -194,7 +194,7 @@ class ItemExtension(BaseModel):
"StableDiffusionProcessingTxt2Img",
StableDiffusionProcessingTxt2Img,
[
{"key": "sampler_index", "type": int, "default": 0},
{"key": "sampler_index", "type": Union[int, str], "default": 0},
{"key": "sampler_name", "type": str, "default": "UniPC"},
{"key": "hr_sampler_name", "type": str, "default": "Same as primary"},
{"key": "script_name", "type": str, "default": "none"},
Expand All @@ -218,7 +218,7 @@ class ResTxt2Img(BaseModel):
"StableDiffusionProcessingImg2Img",
StableDiffusionProcessingImg2Img,
[
{"key": "sampler_index", "type": int, "default": 0},
{"key": "sampler_index", "type": Union[int, str], "default": 0},
{"key": "sampler_name", "type": str, "default": "UniPC"},
{"key": "hr_sampler_name", "type": str, "default": "Same as primary"},
{"key": "script_name", "type": str, "default": "none"},
Expand Down Expand Up @@ -405,10 +405,6 @@ class ResNVML(BaseModel): # definition of http response
state: str = Field(title="State")


# compatibility items
StableDiffusionTxt2ImgProcessingAPI = ResTxt2Img
StableDiffusionImg2ImgProcessingAPI = ResImg2Img

# helper function

def create_model_from_signature(func: Callable, model_name: str, base_model: Type[BaseModel] = BaseModel, additional_fields: List = [], exclude_fields: List[str] = []):
Expand Down
24 changes: 11 additions & 13 deletions modules/postprocess/yolo.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from typing import TYPE_CHECKING
import os
from copy import copy
import numpy as np
import gradio as gr
from PIL import Image, ImageDraw
Expand Down Expand Up @@ -259,23 +260,23 @@ def restore(self, np_image, p: processing.StableDiffusionProcessing = None):

report = [{'label': i.label, 'score': i.score, 'size': f'{i.width}x{i.height}' } for i in items]
shared.log.info(f'Detailer: model="{name}" items={report} args={items[0].args} denoise={p.denoising_strength} blur={p.mask_blur} width={p.width} height={p.height} padding={p.inpaint_full_res_padding}')
shared.log.debug(f'Detailer: prompt="{prompt}" negative="{negative}"')
# shared.log.debug(f'Detailer: prompt="{prompt}" negative="{negative}"')
models_used.append(name)

mask_all = []
p.state = ''
prev_state = shared.state.job
pc = copy(p)
for item in items:
if item.mask is None:
continue
p.init_images = [image]
p.image_mask = [item.mask]
# mask_all.append(item.mask)
p.recursion = True
pc.init_images = [image]
pc.image_mask = [item.mask]
pc.overlay_images = []
pc.recursion = True
shared.state.job = 'Detailer'
pp = processing.process_images_inner(p)
del p.recursion
p.overlay_images = None # skip applying overlay twice
pp = processing.process_images_inner(pc)
del pc.recursion
if pp is not None and pp.images is not None and len(pp.images) > 0:
image = pp.images[0] # update image to be reused for next item
if len(pp.images) > 1:
Expand All @@ -298,13 +299,10 @@ def restore(self, np_image, p: processing.StableDiffusionProcessing = None):
if len(mask_all) > 0 and shared.opts.include_mask:
from modules.control.util import blend
p.image_mask = blend([np.array(m) for m in mask_all])
# combined = blend([np_image, p.image_mask])
# combined = Image.fromarray(combined)
# combined.save('/tmp/item.png')
p.image_mask = Image.fromarray(p.image_mask)

if len(models_used) > 0:
shared.log.debug(f'Detailer processed: models={models_used}')
# if len(models_used) > 0:
# shared.log.debug(f'Detailer processed: models={models_used}')
return np_image

def ui(self, tab: str):
Expand Down
2 changes: 1 addition & 1 deletion modules/processing.py
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
ipadapter.unapply(shared.sd_model, unload=getattr(p, 'ip_adapter_unload', False))

if shared.opts.include_mask:
if shared.opts.mask_apply_overlay and p.overlay_images is not None and len(p.overlay_images):
if shared.opts.mask_apply_overlay and p.overlay_images is not None and len(p.overlay_images) > 0:
p.image_mask = create_binary_mask(p.overlay_images[0])
p.image_mask = ImageOps.invert(p.image_mask)
output_images.append(p.image_mask)
Expand Down
3 changes: 3 additions & 0 deletions modules/processing_args.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,9 @@ def set_pipeline_args(p, model, prompts:list, negative_prompts:list, prompts_2:t
if isinstance(args['image'], torch.Tensor) or isinstance(args['image'], np.ndarray):
args['width'] = 8 * args['image'].shape[-1]
args['height'] = 8 * args['image'].shape[-2]
elif isinstance(args['image'][0], torch.Tensor) or isinstance(args['image'][0], np.ndarray):
args['width'] = 8 * args['image'][0].shape[-1]
args['height'] = 8 * args['image'][0].shape[-2]
else:
args['width'] = 8 * math.ceil(args['image'][0].width / 8)
args['height'] = 8 * math.ceil(args['image'][0].height / 8)
Expand Down
2 changes: 1 addition & 1 deletion modules/processing_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,7 @@ def init(self, all_prompts=None, all_seeds=None, all_subseeds=None):
image = images.resize_image(self.resize_mode, image, self.width, self.height, upscaler_name=self.resize_name, context=self.resize_context)
self.width = image.width
self.height = image.height
if self.image_mask is not None and shared.opts.mask_apply_overlay and not hasattr(self, 'xyz'):
if self.image_mask is not None and shared.opts.mask_apply_overlay:
image_masked = Image.new('RGBa', (image.width, image.height))
image_to_paste = image.convert("RGBA").convert("RGBa")
image_to_mask = ImageOps.invert(self.mask_for_overlay.convert('L')) if self.mask_for_overlay is not None else None
Expand Down
2 changes: 1 addition & 1 deletion modules/sd_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1288,7 +1288,7 @@ def set_diffuser_pipe(pipe, new_pipe_type):
new_pipe.image_encoder = image_encoder
if feature_extractor is not None:
new_pipe.feature_extractor = feature_extractor
if new_pipe.__class__.__name__ == 'FluxPipeline':
if new_pipe.__class__.__name__ in ['FluxPipeline', 'StableDiffusion3Pipeline']:
new_pipe.register_modules(image_encoder = image_encoder)
new_pipe.register_modules(feature_extractor = feature_extractor)
new_pipe.is_sdxl = getattr(pipe, 'is_sdxl', False) # a1111 compatibility item
Expand Down
5 changes: 5 additions & 0 deletions modules/sd_samplers_diffusers.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,11 +271,16 @@ def __init__(self, name, constructor, model, **kwargs):
sampler = constructor(**self.config)
accept_sigmas = "sigmas" in set(inspect.signature(sampler.set_timesteps).parameters.keys())
accepts_timesteps = "timesteps" in set(inspect.signature(sampler.set_timesteps).parameters.keys())
accept_scale_noise = hasattr(sampler, "scale_noise")
debug(f'Sampler: sampler="{name}" sigmas={accept_sigmas} timesteps={accepts_timesteps}')
if ('Flux' in model.__class__.__name__) and (not accept_sigmas):
shared.log.warning(f'Sampler: sampler="{name}" does not accept sigmas')
self.sampler = None
return
if ('StableDiffusion3' in model.__class__.__name__) and (not accept_scale_noise):
shared.log.warning(f'Sampler: sampler="{name}" does not implement scale noise')
self.sampler = None
return
self.sampler = sampler
if name == 'DC Solver':
if not hasattr(self.sampler, 'dc_ratios'):
Expand Down
8 changes: 6 additions & 2 deletions modules/shared.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,8 +303,12 @@ def validate(self, opt, value):
# return False
minimum = args.get("minimum", None)
maximum = args.get("maximum", None)
if (minimum is not None and value < minimum) or (maximum is not None and value > maximum):
log.error(f'Setting validation: "{opt}"={value} default={self.default} minimum={minimum} maximum={maximum}')
try:
if (minimum is not None and value < minimum) or (maximum is not None and value > maximum):
log.error(f'Setting validation: "{opt}"={value} default={self.default} minimum={minimum} maximum={maximum}')
return False
except Exception as err:
log.error(f'Setting validation: "{opt}"={value} default={self.default} minimum={minimum} maximum={maximum} error={err}')
return False
return True

Expand Down
2 changes: 2 additions & 0 deletions scripts/xyz_grid_on.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,12 +325,14 @@ def cell(x, y, z, ix, iy, iz):
x_opt.apply(pc, x, xs)
y_opt.apply(pc, y, ys)
z_opt.apply(pc, z, zs)

try:
processed = processing.process_images(pc)
except Exception as e:
shared.log.error(f"XYZ grid: Failed to process image: {e}")
errors.display(e, 'XYZ grid')
processed = None

if ix == 0 and iy == 0: # create subgrid info text
pc.extra_generation_params = copy(pc.extra_generation_params)
pc.extra_generation_params['Script'] = self.title()
Expand Down

0 comments on commit 3f36089

Please sign in to comment.