Update !1-custom-hires-fix-mod-for-automatic1111-2.9.5/scripts/!!custom_hires_fix.py
Browse files
!1-custom-hires-fix-mod-for-automatic1111-2.9.5/scripts/!!custom_hires_fix.py
CHANGED
|
@@ -1928,6 +1928,64 @@ class CustomHiresFix(scripts.Script):
|
|
| 1928 |
pass
|
| 1929 |
self._orig_opt_vae_tiling = None
|
| 1930 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1931 |
|
| 1932 |
# --- safe upscaler wrapper (PIL fallback) ---
|
| 1933 |
def _resize_with_upscaler(self, img: Image.Image, w: int, h: int, upscaler_name: str) -> Image.Image:
|
|
@@ -2558,11 +2616,7 @@ class CustomHiresFix(scripts.Script):
|
|
| 2558 |
).to(devices.dtype_vae)
|
| 2559 |
|
| 2560 |
devices.torch_gc()
|
| 2561 |
-
decoded_sample =
|
| 2562 |
-
if torch.isnan(decoded_sample).any().item():
|
| 2563 |
-
devices.torch_gc()
|
| 2564 |
-
samples = torch.clamp(samples, -3, 3)
|
| 2565 |
-
decoded_sample = processing.decode_first_stage(shared.sd_model, samples)
|
| 2566 |
|
| 2567 |
decoded_sample = torch.clamp((decoded_sample + 1.0) / 2.0, min=0.0, max=1.0).squeeze()
|
| 2568 |
x_np = 255.0 * np.moveaxis(decoded_sample.to(torch.float32).cpu().numpy(), 0, 2)
|
|
@@ -2790,11 +2844,7 @@ class CustomHiresFix(scripts.Script):
|
|
| 2790 |
).to(devices.dtype_vae)
|
| 2791 |
|
| 2792 |
devices.torch_gc()
|
| 2793 |
-
decoded_sample =
|
| 2794 |
-
if torch.isnan(decoded_sample).any().item():
|
| 2795 |
-
devices.torch_gc()
|
| 2796 |
-
samples = torch.clamp(samples, -3, 3)
|
| 2797 |
-
decoded_sample = processing.decode_first_stage(shared.sd_model, samples)
|
| 2798 |
|
| 2799 |
decoded_sample = torch.clamp((decoded_sample + 1.0) / 2.0, min=0.0, max=1.0).squeeze()
|
| 2800 |
x_np = 255.0 * np.moveaxis(decoded_sample.to(torch.float32).cpu().numpy(), 0, 2)
|
|
|
|
| 1928 |
pass
|
| 1929 |
self._orig_opt_vae_tiling = None
|
| 1930 |
|
| 1931 |
+
def _decode_first_stage_safe(self, samples: torch.Tensor) -> torch.Tensor:
|
| 1932 |
+
"""
|
| 1933 |
+
Обёртка над processing.decode_first_stage с защитой от OOM:
|
| 1934 |
+
1) Агрессивная очистка VRAM перед декодом (torch_gc + empty_cache).
|
| 1935 |
+
2) Авто-включение VAE tiling при первом OOM и повтор с теми же данными.
|
| 1936 |
+
3) Второй OOM: повтор с clamp(-3,3) — ВНИМАНИЕ: незначительно меняет
|
| 1937 |
+
результат, используется только как последний аварийный шанс.
|
| 1938 |
+
4) NaN guard: если декод вернул NaN — clamp + повтор.
|
| 1939 |
+
Перевод результата на CPU выполняется в вызывающем коде, не здесь.
|
| 1940 |
+
"""
|
| 1941 |
+
# Шаг 1: максимально освободить VRAM перед тяжёлым декодом
|
| 1942 |
+
devices.torch_gc()
|
| 1943 |
+
try:
|
| 1944 |
+
torch.cuda.empty_cache()
|
| 1945 |
+
except Exception:
|
| 1946 |
+
pass
|
| 1947 |
+
|
| 1948 |
+
def _do_decode(s: torch.Tensor) -> torch.Tensor:
|
| 1949 |
+
return processing.decode_first_stage(shared.sd_model, s)
|
| 1950 |
+
|
| 1951 |
+
# Шаг 2: попытка декода; при OOM — включаем VAE tiling и повторяем
|
| 1952 |
+
# с теми же данными (результат не меняется)
|
| 1953 |
+
try:
|
| 1954 |
+
decoded = _do_decode(samples)
|
| 1955 |
+
except torch.cuda.OutOfMemoryError:
|
| 1956 |
+
logger.warning(
|
| 1957 |
+
"OOM during decode_first_stage — enabling VAE tiling and retrying "
|
| 1958 |
+
"(same data, result unchanged). Consider enabling 'VAE tiling (low VRAM)' "
|
| 1959 |
+
"in extension settings to avoid this overhead."
|
| 1960 |
+
)
|
| 1961 |
+
devices.torch_gc()
|
| 1962 |
+
try:
|
| 1963 |
+
torch.cuda.empty_cache()
|
| 1964 |
+
except Exception:
|
| 1965 |
+
pass
|
| 1966 |
+
self._set_vae_tiling(True)
|
| 1967 |
+
try:
|
| 1968 |
+
decoded = _do_decode(samples)
|
| 1969 |
+
except torch.cuda.OutOfMemoryError:
|
| 1970 |
+
# Шаг 3: последний аварийный шанс — clamp(-3,3) + повтор.
|
| 1971 |
+
# ВНИМАНИЕ: clamp незначительно изменяет экстремальные значения латента,
|
| 1972 |
+
# что может чуть повлиять на детали картинки. Применяется только при
|
| 1973 |
+
# втором подряд OOM, когда даже VAE tiling не помог.
|
| 1974 |
+
logger.warning(
|
| 1975 |
+
"OOM again after VAE tiling — clamping latents to [-3, 3] and retrying. "
|
| 1976 |
+
"This is a last-resort fallback and may slightly alter the output image."
|
| 1977 |
+
)
|
| 1978 |
+
devices.torch_gc()
|
| 1979 |
+
decoded = _do_decode(torch.clamp(samples, -3, 3))
|
| 1980 |
+
|
| 1981 |
+
# Шаг 4: NaN guard (отдельно от OOM — может возникнуть без нехватки памяти)
|
| 1982 |
+
if torch.isnan(decoded).any().item():
|
| 1983 |
+
logger.warning("NaN detected in decoded sample — clamping latents and retrying.")
|
| 1984 |
+
devices.torch_gc()
|
| 1985 |
+
decoded = _do_decode(torch.clamp(samples, -3, 3))
|
| 1986 |
+
|
| 1987 |
+
return decoded
|
| 1988 |
+
|
| 1989 |
|
| 1990 |
# --- safe upscaler wrapper (PIL fallback) ---
|
| 1991 |
def _resize_with_upscaler(self, img: Image.Image, w: int, h: int, upscaler_name: str) -> Image.Image:
|
|
|
|
| 2616 |
).to(devices.dtype_vae)
|
| 2617 |
|
| 2618 |
devices.torch_gc()
|
| 2619 |
+
decoded_sample = self._decode_first_stage_safe(samples)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2620 |
|
| 2621 |
decoded_sample = torch.clamp((decoded_sample + 1.0) / 2.0, min=0.0, max=1.0).squeeze()
|
| 2622 |
x_np = 255.0 * np.moveaxis(decoded_sample.to(torch.float32).cpu().numpy(), 0, 2)
|
|
|
|
| 2844 |
).to(devices.dtype_vae)
|
| 2845 |
|
| 2846 |
devices.torch_gc()
|
| 2847 |
+
decoded_sample = self._decode_first_stage_safe(samples)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2848 |
|
| 2849 |
decoded_sample = torch.clamp((decoded_sample + 1.0) / 2.0, min=0.0, max=1.0).squeeze()
|
| 2850 |
x_np = 255.0 * np.moveaxis(decoded_sample.to(torch.float32).cpu().numpy(), 0, 2)
|