numz/ComfyUI-SeedVR2_VideoUpscaler - GitHub


🛠️ 实战记录:修复 ComfyUI SeedVR2 视频超分插件 'tuple' object has no attribute 'sample' 报错

📅 背景

最近在使用 ComfyUI 运行最新的 SeedVR2 Video Upscaler 自定义节点进行视频超分辨率处理时,遇到了一个典型的 Python 属性错误。虽然模型加载正常,采样器(EulerSampler)也跑完了,但在最后的 VAE 解码阶段 程序崩溃了。

对于正在折腾本地 AI 视频工作流的朋友来说,这种“临门一脚”的报错最搞心态。今天就来复盘一下这个 Bug 的定位思路和最终解决方案。

🚨 报错现场

运行日志显示,在处理 Batch 1 的第 0 帧时,进程突然终止:

!!! Exception during processing !!! 'tuple' object has no attribute 'sample'
Traceback (most recent call last):
  ...
  File "...\ComfyUI-SeedVR2-VideoUpscaler\src\core\infer.py", line 205, in vae_decode
    sample = self.vae.decode(latent, ...).sample
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "...\attn_video_vae.py", line 1689, in decode
    tile_overlap=tile_overlap).sample.squeeze(2)
                               ^^^^^^
AttributeError: 'tuple' object has no attribute 'sample'
故障节点

关键信息提取:

  1. 错误类型AttributeError,对象是 tuple,却试图访问 .sample 属性。
  2. 出错位置attn_video_vae.py 文件的第 1689 行,位于 VideoAutoencoderKLWrapper.decode 方法中。
  3. 触发场景:VAE 解码阶段,很可能触发了分块解码(Tiled Decode)逻辑。

🔍 深度分析:为什么返回了元组?

1. 代码逻辑推演

attn_video_vae.py 中,VideoAutoencoderKLWrapper 继承自底层的 VAE 类。其 decode 方法的核心逻辑大致如下:

# 伪代码还原
def decode(self, z, return_dict=True, tiled=False, ...):
    # 调用父类方法进行解码
    result = super().decode(z, return_dict=return_dict, tiled=tiled, ...)
    
    # 期望 result 是一个包含 .sample 属性的对象 (如 DecoderOutput)
    x = result.sample.squeeze(2) 
    return CausalDecoderOutput(x)

然而,报错告诉我们 result 实际上是一个 元组 (tuple),例如 (tensor,)

2. 根源定位

追踪到底层 VideoAutoencoderKL.decode (来自 diffusers 或其魔改版) 的实现,发现了一个常见的兼容性陷阱:

# 底层 VAE 的 decode 逻辑
def decode(self, z, return_dict=True, tiled=False, ...):
    if tiled:
        decoded = self.tiled_decode(z, ...) # 返回 Tensor
    else:
        decoded = self.slicing_decode(z)    # 返回 Tensor
    
    # ⚠️ 关键点在这里
    if not return_dict:
        return (decoded,)  # 返回元组!
    
    return DecoderOutput(sample=decoded) # 返回对象

问题出在哪?
虽然 VideoAutoencoderKLWrapper.decode 默认设置了 return_dict=True,但在某些特定的执行路径、参数传递覆盖,或者不同版本的 diffusers 库行为差异下,父类方法可能意外地进入了 if not return_dict 分支,或者直接返回了未经包装的元组(特别是在处理 Tiling 逻辑时,某些旧版本实现可能存在返回值不一致的情况)。

当代码试图对这个元组调用 .sample 时,Python 自然会抛出 AttributeError

✅ 解决方案:增加鲁棒性判断

修复的核心思路很简单:不要盲目假设返回值一定是对象,要兼容元组和 Tensor 的情况。

我们需要修改 H:\...\ComfyUI-SeedVR2_VideoUpscaler\src\models\video_vae_v3\modules\attn_video_vae.py 文件中的 VideoAutoencoderKLWrapper.decode 方法。

📝 修改前 (Buggy Code)

def decode(self, z: torch.Tensor, return_dict: bool = True,
           tiled: bool = False, tile_size: Tuple[int, int] = (512, 512),
           tile_overlap: Tuple[int, int] = (64, 64)) -> CausalDecoderOutput:
    if z.ndim == 4:
        z = z.unsqueeze(2)
    
    # ❌ 风险点:直接假设 super().decode() 返回的对象有 .sample 属性
    x = super().decode(z, return_dict=return_dict, tiled=tiled, tile_size=tile_size,
                      tile_overlap=tile_overlap).sample.squeeze(2)
    
    return CausalDecoderOutput(x)

🛠️ 修改后 (Fixed Code)

def decode(self, z: torch.Tensor, return_dict: bool = True,
           tiled: bool = False, tile_size: Tuple[int, int] = (512, 512),
           tile_overlap: Tuple[int, int] = (64, 64)) -> CausalDecoderOutput:
    if z.ndim == 4:
        z = z.unsqueeze(2)
    
    # 1. 显式强制 return_dict=True,减少不确定性
    result = super().decode(z, return_dict=True, tiled=tiled, tile_size=tile_size,
                          tile_overlap=tile_overlap)
    
    # 2. 增加类型检查,兼容多种返回格式
    if isinstance(result, tuple):
        # 情况 A: 返回了 (tensor,) 元组,取第一个元素
        decoded_tensor = result[0]
    elif hasattr(result, 'sample'):
        # 情况 B: 返回了标准的 DecoderOutput 对象
        decoded_tensor = result.sample
    else:
        # 情况 C: 直接返回了 Tensor (极端情况)
        decoded_tensor = result
        
    # 3. 执行后续处理
    x = decoded_tensor.squeeze(2)
    
    return CausalDecoderOutput(x)

修复后测试数轮无问题

💡 总结与启示

  1. 防御性编程很重要:在调用第三方库(尤其是处于快速迭代期的 AI 库如 diffusers)时,永远不要完全信任返回值的类型。加上 isinstancehasattr 判断能解决 90% 的版本兼容性问题。
  2. 关注 Tiling 逻辑:很多 VAE 报错都发生在开启 tiled_vaeslicing 时,因为这两条代码路径往往测试得不如标准路径充分,返回值结构容易发生变化。
  3. Traceback 是好朋友:准确读取报错行号和文件路径,能让我们直接从几百行的堆栈中锁定那唯一的“罪魁祸首”。

希望这篇记录能帮到遇到同样问题的朋友!如果你也在运行 SeedVR2 或其他视频生成模型遇到坑,欢迎在评论区交流。


标签:#ComfyUI #SeedVR2 #AI视频 #Python调试 #BugFix #DeepLearning

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐