Skip to content

Commit f68fe92

Browse files
authored
Merge pull request #358 from AInVFX/main
v2.5.15: MPS compatibility fixes, autocast device type, VRAM tracking, triton 3.0+ compatibility
2 parents d4dd5e7 + 65c1c1b commit f68fe92

File tree

14 files changed

+56
-63
lines changed

14 files changed

+56
-63
lines changed

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,13 @@ We're actively working on improvements and new features. To stay informed:
3636

3737
## 🚀 Updates
3838

39+
**2025.12.03 - Version 2.5.15**
40+
41+
- **🍎 Fix: MPS compatibility** - Disable antialias for MPS tensors and fix bfloat16 arange issues
42+
- **⚡ Fix: Autocast device type** - Use proper device type attribute to prevent autocast errors
43+
- **📊 Memory: Accurate VRAM tracking** - Use max_memory_reserved for more precise peak reporting
44+
- **🔧 Fix: Triton compatibility** - Add shim for bitsandbytes 0.45+ / triton 3.0+ (fixes PyTorch 2.7 installation errors)
45+
3946
**2025.12.01 - Version 2.5.14**
4047

4148
- **🍎 Fix: MPS device comparison** - Normalize device strings to prevent unnecessary tensor movements

__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
Official SeedVR2 integration for ComfyUI
44
"""
55

6+
from .src.optimization.compatibility import ensure_triton_compat # noqa: F401
67
from .src.interfaces import comfy_entrypoint, SeedVR2Extension
78

89
__all__ = ["comfy_entrypoint", "SeedVR2Extension"]

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[project]
22
name = "seedvr2_videoupscaler"
33
description = "SeedVR2 official ComfyUI integration: ByteDance-Seed's one-step diffusion-based video/image upscaling with memory-efficient inference"
4-
version = "2.5.14"
4+
version = "2.5.15"
55
authors = [
66
{name = "numz"},
77
{name = "adrientoupet"}

src/common/diffusion/timesteps/sampling/trailing.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def __init__(
3636
dtype: torch.dtype = torch.float32,
3737
):
3838
# Create trailing timesteps with specified dtype
39-
timesteps = torch.arange(1.0, 0.0, -1.0 / steps, device=device, dtype=dtype)
39+
timesteps = torch.arange(1.0, 0.0, -1.0 / steps, device='cpu').to(device=device, dtype=dtype)
4040

4141
# Shift timesteps.
4242
timesteps = shift * timesteps / (1 + (shift - 1) * timesteps)

src/core/generation_phases.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -711,7 +711,7 @@ def _add_noise(x, aug_noise):
711711
debug.start_timer(f"dit_inference_{upscale_idx+1}")
712712
with torch.no_grad():
713713
if dit_dtype != ctx['compute_dtype']:
714-
with torch.autocast(str(ctx['dit_device']), ctx['compute_dtype'], enabled=True):
714+
with torch.autocast(ctx['dit_device'].type, ctx['compute_dtype'], enabled=True):
715715
upscaled_latents = runner.inference(
716716
noises=noises,
717717
conditions=conditions,

src/core/infer.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ def vae_encode(self, samples: List[Tensor]) -> List[Tensor]:
155155

156156
# Use autocast if VAE dtype differs from input dtype
157157
if vae_dtype != sample.dtype:
158-
with torch.autocast(str(device), sample.dtype, enabled=True):
158+
with torch.autocast(device.type, sample.dtype, enabled=True):
159159
if use_sample:
160160
latent = self.vae.encode(sample, tiled=self.encode_tiled, tile_size=self.encode_tile_size,
161161
tile_overlap=self.encode_tile_overlap).latent
@@ -231,7 +231,7 @@ def vae_decode(self, latents: List[Tensor]) -> List[Tensor]:
231231

232232
# Use autocast if VAE dtype differs from latent dtype
233233
if vae_dtype != latent.dtype:
234-
with torch.autocast(str(device), latent.dtype, enabled=True):
234+
with torch.autocast(device.type, latent.dtype, enabled=True):
235235
sample = self.vae.decode(
236236
latent,
237237
tiled=self.decode_tiled, tile_size=self.decode_tile_size,

src/data/image/transforms/area_resize.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,12 @@ def __call__(self, image: Union[torch.Tensor, Image.Image]):
5050

5151
resized_height, resized_width = round(height * scale), round(width * scale)
5252

53+
antialias = not (isinstance(image, torch.Tensor) and image.device.type == 'mps')
5354
return TVF.resize(
5455
image,
5556
size=(resized_height, resized_width),
5657
interpolation=self.interpolation,
58+
antialias=antialias,
5759
)
5860

5961

src/data/image/transforms/side_resize.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,9 @@ def __call__(self, image: Union[torch.Tensor, Image.Image]):
5656
else:
5757
size = self.size
5858

59-
# Resize to shortest edge
60-
resized = TVF.resize(image, size, self.interpolation)
59+
# Resize to shortest edge (disable antialias only for MPS tensors - not supported)
60+
antialias = not (isinstance(image, torch.Tensor) and image.device.type == 'mps')
61+
resized = TVF.resize(image, size, self.interpolation, antialias=antialias)
6162

6263
# Apply max_size constraint if specified
6364
if self.max_size > 0:
@@ -69,6 +70,6 @@ def __call__(self, image: Union[torch.Tensor, Image.Image]):
6970
if max(h, w) > self.max_size:
7071
scale = self.max_size / max(h, w)
7172
new_h, new_w = round(h * scale), round(w * scale)
72-
resized = TVF.resize(resized, (new_h, new_w), self.interpolation)
73+
resized = TVF.resize(resized, (new_h, new_w), self.interpolation, antialias=antialias)
7374

7475
return resized

src/models/video_vae_v3/modules/attn_video_vae.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import torch.nn as nn
1818
import torch.nn.functional as F
1919
from diffusers.models.attention_processor import Attention, SpatialNorm
20+
from diffusers.models.autoencoders.vae import DecoderOutput, DiagonalGaussianDistribution
2021
from diffusers.models.downsampling import Downsample2D
2122
from diffusers.models.lora import LoRACompatibleConv
2223
from diffusers.models.modeling_outputs import AutoencoderKLOutput
@@ -45,8 +46,6 @@
4546
CausalAutoencoderOutput,
4647
CausalDecoderOutput,
4748
CausalEncoderOutput,
48-
DecoderOutput,
49-
DiagonalGaussianDistribution,
5049
MemoryState,
5150
_inflation_mode_t,
5251
_memory_device_t,

src/models/video_vae_v3/modules/types.py

Lines changed: 0 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -74,51 +74,3 @@ class CausalEncoderOutput(NamedTuple):
7474

7575
class CausalDecoderOutput(NamedTuple):
7676
sample: torch.Tensor
77-
78-
79-
class DecoderOutput:
80-
"""Output of decoding method - matches diffusers.models.autoencoders.vae.DecoderOutput"""
81-
def __init__(self, sample: torch.Tensor, commit_loss: Optional[torch.Tensor] = None):
82-
self.sample = sample
83-
self.commit_loss = commit_loss
84-
85-
86-
class DiagonalGaussianDistribution:
87-
"""Matches diffusers.models.autoencoders.vae.DiagonalGaussianDistribution exactly."""
88-
def __init__(self, parameters: torch.Tensor, deterministic: bool = False):
89-
self.parameters = parameters
90-
self.mean, self.logvar = torch.chunk(parameters, 2, dim=1)
91-
self.logvar = torch.clamp(self.logvar, -30.0, 20.0)
92-
self.deterministic = deterministic
93-
self.std = torch.exp(0.5 * self.logvar)
94-
self.var = torch.exp(self.logvar)
95-
if self.deterministic:
96-
self.var = self.std = torch.zeros_like(
97-
self.mean, device=self.parameters.device, dtype=self.parameters.dtype
98-
)
99-
100-
def sample(self, generator: Optional[torch.Generator] = None) -> torch.Tensor:
101-
if self.deterministic:
102-
return self.mode()
103-
sample = torch.randn(
104-
self.mean.shape,
105-
generator=generator,
106-
device=self.parameters.device,
107-
dtype=self.parameters.dtype,
108-
)
109-
return self.mean + self.std * sample
110-
111-
def mode(self) -> torch.Tensor:
112-
return self.mean
113-
114-
def kl(self, other: Optional["DiagonalGaussianDistribution"] = None) -> torch.Tensor:
115-
if other is None:
116-
return 0.5 * torch.sum(
117-
self.mean.pow(2) + self.var - 1.0 - self.logvar,
118-
dim=[1, 2, 3],
119-
)
120-
return 0.5 * torch.sum(
121-
(self.mean - other.mean).pow(2) / other.var
122-
+ self.var / other.var - 1.0 - self.logvar + other.logvar,
123-
dim=[1, 2, 3],
124-
)

0 commit comments

Comments
 (0)