日期:2026-10-18 环境:B 机(Atlas 800IA2, Ascend 910B4, CANN + torch_npu 26.x) 目标:让 WanVideoWrapper(kijai/ComfyUI-WanVideoWrapper)在 NPU 上跑文生视频一、问题在华为Asecnd NPU 800A2上,部署comfyui,跑 Wan2.1-T2V-1.3B 文生视频 workflow 时报错。WanVideoSampler 在forward中报:File ".../wanvideo/modules/model.py", line 248, in rope_apply_3d freqs_i = torch.cat([ ^^^^^^^^^^^ File ".../torch_npu/csrc/aten/ops/op_api/CopyKernelOpApi.cpp:89" NPU function error: call aclnnInplaceCopy failed, error code is 161002 AclNN_Parameter_Error(EZ1001): tensor 0 not implemented for DT_COMPLEX128, should be in dtype support list [DT_FLOAT, DT_INT32, DT_INT64, DT_FLOAT16, DT_INT16, DT_INT8, DT_UINT8, DT_DOUBLE, DT_COMPLEX64, DT_BFLOAT16, DT_BOOL]二、根因Wan2.1 RoPE 用 complex dtype:torch.polar(ones, freqs)默认输出complex64NPU 算子aclnnCat不支持DT_COMPLEX128:NPU 算子支持列表里只有DT_COMPLEX64,没有DT_COMPLEX128dtype promotion:当多个 complex tensor cat 阶段,NPU 上 implicit 提升到complex128,超出算子支持范围三、解法:monkey patch torch.cat在 WanVideoWrapper 的__init__.py末尾加:# NPU compatibility monkey patch: torch.cat on NPU promotes complex64 to complex128 # but aclnnCat does not support complex128. Cast back to complex64 before cat. import torch as _torch _orig_cat = _torch.cat def _npu_safe_cat(tensors, dim=0, *args, **kwargs): tensors = list(tensors) for i, t in enumerate(tensors): try: if hasattr(t, 'dtype') and t.dtype == _torch.complex128: tensors[i] = t.to(_torch.complex64) except Exception: pass return _orig_cat(tensors, dim=dim, *args, **kwargs) _torch.cat = _npu_safe_cat四、为什么这个 patch 起作用在 cat 之前拦截:检查每个输入 tensor 的 dtypecomplex128→complex64强制转换:NPU 算子能接受complex64不影响其它 dtype:其它 dtype tensor 透传不改动只在 WanVideoWrapper 模块加载时执行一次:进程内所有torch.cat都受影响(包括 WanVideoSampler、VAE、T5、CLIP 等所有调用)五、验证打 patch 后重启 ComfyUI(import 时执行 patch),跑测试 prompt:之前:error 161002,DT_COMPLEX128 unsupported 之后:status: success output: test_1.3b_shot1_00001.mp4 (5.06s, 81 frames, 832x480)六、风险与副作用风险影响缓解修改全局torch.cat影响整个进程已限制在 WanVideoWrapper 模块(custom node),ComfyUI 其它流程不动降低 complex 精度complex128 → complex64 有微小精度差RoPE 只用 complex 的角度分量,精度损失对最终视觉无感patch 失序其它 custom node 在 WanVideoWrapper 之前 import 并先调用 cat不影响结果(patch 在 WanVideoWrapper 加载后立即生效)升级 WanVideoWrapper 后 patch 丢失需要重新加在 commit message 里记录 patch 位置七、复现步骤安装 WanVideoWrapper(任意版本)把上面 patch 追加到/workspace/ComfyUI/custom_nodes/ComfyUI-WanVideoWrapper/__init__.py末尾重启 ComfyUI跑任意 WanVideo workflow八、传到容器内的方法容器内编辑文件常用方法:heredoc:常被 bash 多层嵌套吃掉引号(不可靠)base64 传递(推荐):PATCH_B64=$(echo "patch content" | base64 -w0) docker exec comfyui bash -c "echo $PATCH_B64 | base64 -d >> /path/to/__init__.py"docker cp:host 文件 → 容器文件(偶尔 race condition 失败)直接在容器内写文件(最稳):docker exec comfyui bash -c "cat >> /path/to/__init__.py" << 'EOF' ...patch content... EOF九、为什么不用改 WanVideo Wrapper 源码本身可以考虑给 kijai 提 PR 加 NPU dtype 检查,但:NPU 算子限制是 Ascend 特有,WanVideo Wrapper 是社区项目,主要跑 NVIDIA改源码需要 fork + 维护分支,长期成本高Monkey patch 写在__init__.py末尾,升级时重写即可十、其它 dtype 问题如果遇到其它 dtype(fp64, fp128 等)NPU 算子不支持,可以扩展 patch:_DTYPE_FALLBACK = { _torch.complex128: _torch.complex64, _torch.float64: _torch.float32, # 谨慎使用,会丢精度 } def _npu_safe_cat(tensors, dim=0, *args, **kwargs): tensors = list(tensors) for i, t in enumerate(tensors): try: if hasattr(t, 'dtype') and t.dtype in _DTYPE_FALLBACK: tensors[i] = t.to(_DTYPE_FALLBACK[t.dtype]) except Exception: pass return _orig_cat(tensors, dim=dim, *args, **kwargs)附:错误码速查错误码含义常见原因161002DT_COMPLEX128 unsupportedNPU 算子不支持(本次问题)207001NPU out of memory单卡 HBM 不够(之前多次遇到)EZ1001AclNN_Parameter_Error算子参数不合法(dtype / shape 错)
日期:2026-10-18 环境:B 机(Atlas 800IA2, Ascend 910B4, CANN + torch_npu 26.x) 目标:让 WanVideoWrapper(kijai/ComfyUI-WanVideoWrapper)在 NPU 上跑文生视频一、问题在华为Asecnd NPU 800A2上,部署comfyui,跑 Wan2.1-T2V-1.3B 文生视频 workflow 时报错。WanVideoSampler 在forward中报:File ".../wanvideo/modules/model.py", line 248, in rope_apply_3d freqs_i = torch.cat([ ^^^^^^^^^^^ File ".../torch_npu/csrc/aten/ops/op_api/CopyKernelOpApi.cpp:89" NPU function error: call aclnnInplaceCopy failed, error code is 161002 AclNN_Parameter_Error(EZ1001): tensor 0 not implemented for DT_COMPLEX128, should be in dtype support list [DT_FLOAT, DT_INT32, DT_INT64, DT_FLOAT16, DT_INT16, DT_INT8, DT_UINT8, DT_DOUBLE, DT_COMPLEX64, DT_BFLOAT16, DT_BOOL]二、根因Wan2.1 RoPE 用 complex dtype:torch.polar(ones, freqs)默认输出complex64NPU 算子aclnnCat不支持DT_COMPLEX128:NPU 算子支持列表里只有DT_COMPLEX64,没有DT_COMPLEX128dtype promotion:当多个 complex tensor cat 阶段,NPU 上 implicit 提升到complex128,超出算子支持范围三、解法:monkey patch torch.cat在 WanVideoWrapper 的__init__.py末尾加:# NPU compatibility monkey patch: torch.cat on NPU promotes complex64 to complex128 # but aclnnCat does not support complex128. Cast back to complex64 before cat. import torch as _torch _orig_cat = _torch.cat def _npu_safe_cat(tensors, dim=0, *args, **kwargs): tensors = list(tensors) for i, t in enumerate(tensors): try: if hasattr(t, 'dtype') and t.dtype == _torch.complex128: tensors[i] = t.to(_torch.complex64) except Exception: pass return _orig_cat(tensors, dim=dim, *args, **kwargs) _torch.cat = _npu_safe_cat四、为什么这个 patch 起作用在 cat 之前拦截:检查每个输入 tensor 的 dtypecomplex128→complex64强制转换:NPU 算子能接受complex64不影响其它 dtype:其它 dtype tensor 透传不改动只在 WanVideoWrapper 模块加载时执行一次:进程内所有torch.cat都受影响(包括 WanVideoSampler、VAE、T5、CLIP 等所有调用)五、验证打 patch 后重启 ComfyUI(import 时执行 patch),跑测试 prompt:之前:error 161002,DT_COMPLEX128 unsupported 之后:status: success output: test_1.3b_shot1_00001.mp4 (5.06s, 81 frames, 832x480)六、风险与副作用风险影响缓解修改全局torch.cat影响整个进程已限制在 WanVideoWrapper 模块(custom node),ComfyUI 其它流程不动降低 complex 精度complex128 → complex64 有微小精度差RoPE 只用 complex 的角度分量,精度损失对最终视觉无感patch 失序其它 custom node 在 WanVideoWrapper 之前 import 并先调用 cat不影响结果(patch 在 WanVideoWrapper 加载后立即生效)升级 WanVideoWrapper 后 patch 丢失需要重新加在 commit message 里记录 patch 位置七、复现步骤安装 WanVideoWrapper(任意版本)把上面 patch 追加到/workspace/ComfyUI/custom_nodes/ComfyUI-WanVideoWrapper/__init__.py末尾重启 ComfyUI跑任意 WanVideo workflow八、传到容器内的方法容器内编辑文件常用方法:heredoc:常被 bash 多层嵌套吃掉引号(不可靠)base64 传递(推荐):PATCH_B64=$(echo "patch content" | base64 -w0) docker exec comfyui bash -c "echo $PATCH_B64 | base64 -d >> /path/to/__init__.py"docker cp:host 文件 → 容器文件(偶尔 race condition 失败)直接在容器内写文件(最稳):docker exec comfyui bash -c "cat >> /path/to/__init__.py" << 'EOF' ...patch content... EOF九、为什么不用改 WanVideo Wrapper 源码本身可以考虑给 kijai 提 PR 加 NPU dtype 检查,但:NPU 算子限制是 Ascend 特有,WanVideo Wrapper 是社区项目,主要跑 NVIDIA改源码需要 fork + 维护分支,长期成本高Monkey patch 写在__init__.py末尾,升级时重写即可十、其它 dtype 问题如果遇到其它 dtype(fp64, fp128 等)NPU 算子不支持,可以扩展 patch:_DTYPE_FALLBACK = { _torch.complex128: _torch.complex64, _torch.float64: _torch.float32, # 谨慎使用,会丢精度 } def _npu_safe_cat(tensors, dim=0, *args, **kwargs): tensors = list(tensors) for i, t in enumerate(tensors): try: if hasattr(t, 'dtype') and t.dtype in _DTYPE_FALLBACK: tensors[i] = t.to(_DTYPE_FALLBACK[t.dtype]) except Exception: pass return _orig_cat(tensors, dim=dim, *args, **kwargs)附:错误码速查错误码含义常见原因161002DT_COMPLEX128 unsupportedNPU 算子不支持(本次问题)207001NPU out of memory单卡 HBM 不够(之前多次遇到)EZ1001AclNN_Parameter_Error算子参数不合法(dtype / shape 错)