mirror of https://github.com/vladmandic/automatic
add RealPLKSR NomosWebPhoto and AnimeSharpV2 using spandrel engine
Signed-off-by: vladmandic <mandic00@live.com>pull/4626/head
parent
e5ebc4e5a2
commit
dd80e15cfd
21
CHANGELOG.md
21
CHANGELOG.md
|
|
@ -2,14 +2,19 @@
|
|||
|
||||
## Update for 2026-02-05
|
||||
|
||||
Bugfix refresh
|
||||
|
||||
- fix: add metadata restore to always-on scripts
|
||||
- fix: improve wildcard weights parsing, thanks @Tillerz
|
||||
- fix: `anima` model detection
|
||||
- refactor: reorganize `cli` scripts
|
||||
- upscalers: hqx, icbi
|
||||
- ui: add CTD-NT64Light theme, thanks @resonantsky
|
||||
- **UI**
|
||||
- ui: add CTD-NT64Light theme, thanks @resonantsky
|
||||
- **Internal**
|
||||
- refactor: reorganize `cli` scripts
|
||||
- **Upscalers**
|
||||
- add support for [spandrel](https://github.com/chaiNNer-org/spandrel)
|
||||
upscaling engine with suport for new upscaling families
|
||||
- add two new ai upscalers: *RealPLKSR NomosWebPhoto* and *RealPLKSR AnimeSharpV2*
|
||||
- add two new interpolation methods: *HQX* and *ICB*
|
||||
- **Fixes**
|
||||
- fix: add metadata restore to always-on scripts
|
||||
- fix: improve wildcard weights parsing, thanks @Tillerz
|
||||
- fix: `anima` model detection
|
||||
|
||||
## Update for 2026-02-04
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
import os
|
||||
import time
|
||||
from PIL import Image
|
||||
from modules.upscaler import Upscaler, UpscalerData
|
||||
from modules import devices, paths
|
||||
from modules.shared import log
|
||||
|
||||
|
||||
MODELS = {
|
||||
"Spandrel 4x RealPLKSR NomosWebPhoto": "https://huggingface.co/vladmandic/sdnext-upscalers/resolve/main/4xNomosWebPhoto_RealPLKSR.safetensors",
|
||||
"Spandrel 2x RealPLKSR AnimeSharpV2": "https://huggingface.co/vladmandic/sdnext-upscalers/resolve/main/2x-AnimeSharpV2_RPLKSR_Sharp.pth",
|
||||
}
|
||||
|
||||
class UpscalerSpandrel(Upscaler):
|
||||
def __init__(self, dirname=None): # pylint: disable=unused-argument
|
||||
super().__init__(False)
|
||||
self.name = "Spandrel"
|
||||
self.model_path = os.path.join(paths.models_path, 'Spandrel')
|
||||
self.user_path = os.path.join(paths.models_path, 'Spandrel')
|
||||
self.selected = None
|
||||
self.model = None
|
||||
self.scalers = []
|
||||
for model_name, model_path in MODELS.items():
|
||||
scaler = UpscalerData(name=model_name, path=model_path, upscaler=self)
|
||||
self.scalers.append(scaler)
|
||||
|
||||
def process(self, img: Image.Image) -> Image.Image:
|
||||
import torchvision.transforms.functional as TF
|
||||
tensor = TF.to_tensor(img).unsqueeze(0).to(devices.device)
|
||||
img = img.convert('RGB')
|
||||
t0 = time.time()
|
||||
with devices.inference_context():
|
||||
tensor = self.model(tensor)
|
||||
tensor = tensor.clamp(0, 1).squeeze(0).cpu()
|
||||
t1 = time.time()
|
||||
upscaled = TF.to_pil_image(tensor)
|
||||
log.debug(f'Upscale: name="{self.selected}" input={img.size} output={upscaled.size} time={t1 - t0:.2f}')
|
||||
return upscaled
|
||||
|
||||
def do_upscale(self, img: Image, selected_model=None):
|
||||
from installer import install
|
||||
if selected_model is None:
|
||||
return img
|
||||
install('spandrel')
|
||||
try:
|
||||
import spandrel
|
||||
if (self.model is None) or (self.selected != selected_model):
|
||||
self.selected = selected_model
|
||||
model = self.find_model(selected_model)
|
||||
self.model = spandrel.ModelLoader().load_from_file(model.local_data_path)
|
||||
self.model.to(devices.device).eval()
|
||||
return self.process(img)
|
||||
except Exception as e:
|
||||
log.error(f'Spandrel: {e}')
|
||||
return img
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
import time
|
||||
from PIL import Image
|
||||
from modules.upscaler import Upscaler, UpscalerData
|
||||
|
||||
|
|
@ -30,12 +31,15 @@ class UpscalerAsymmetricVAE(Upscaler):
|
|||
self.vae.eval()
|
||||
self.selected = selected_model
|
||||
shared.log.debug(f'Upscaler load: selected="{self.selected}" vae="{repo_id}"')
|
||||
t0 = time.time()
|
||||
img = img.resize((8 * (img.width // 8), 8 * (img.height // 8)), resample=Image.Resampling.LANCZOS).convert('RGB')
|
||||
tensor = (F.pil_to_tensor(img).unsqueeze(0) / 255.0).to(device=devices.device, dtype=devices.dtype)
|
||||
self.vae = self.vae.to(device=devices.device)
|
||||
tensor = self.vae(tensor).sample
|
||||
upscaled = F.to_pil_image(tensor.squeeze().clamp(0.0, 1.0).float().cpu())
|
||||
self.vae = self.vae.to(device=devices.cpu)
|
||||
t1 = time.time()
|
||||
shared.log.debug(f'Upscale: name="{self.selected}" input={img.size} output={upscaled.size} time={t1 - t0:.2f}')
|
||||
return upscaled
|
||||
|
||||
|
||||
|
|
@ -73,6 +77,7 @@ class UpscalerWanUpscale(Upscaler):
|
|||
self.selected = selected_model
|
||||
shared.log.debug(f'Upscaler load: selected="{self.selected}" encode="{repo_encode}" decode="{repo_decode}"')
|
||||
|
||||
t0 = time.time()
|
||||
self.vae_encode = self.vae_encode.to(device=devices.device)
|
||||
tensor = (F.pil_to_tensor(img).unsqueeze(0).unsqueeze(2) / 255.0).to(device=devices.device, dtype=devices.dtype)
|
||||
tensor = self.vae_encode.encode(tensor).latent_dist.mode()
|
||||
|
|
@ -84,4 +89,6 @@ class UpscalerWanUpscale(Upscaler):
|
|||
self.vae_decode.to(device=devices.cpu)
|
||||
|
||||
upscaled = F.to_pil_image(tensor.squeeze().clamp(0.0, 1.0).float().cpu())
|
||||
t1 = time.time()
|
||||
shared.log.debug(f'Upscale: name="{self.selected}" input={img.size} output={upscaled.size} time={t1 - t0:.2f}')
|
||||
return upscaled
|
||||
|
|
|
|||
Loading…
Reference in New Issue